惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
S
Secure Thoughts
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
News | PayPal Newsroom
Application and Cybersecurity Blog
Application and Cybersecurity Blog
O
OpenAI News
S
Security @ Cisco Blogs
宝玉的分享
宝玉的分享
Hacker News: Ask HN
Hacker News: Ask HN
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
TaoSecurity Blog
TaoSecurity Blog
Help Net Security
Help Net Security
Latest news
Latest news
NISL@THU
NISL@THU
S
Security Affairs
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 聂微东
AI
AI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Recent Announcements
Recent Announcements
P
Privacy & Cybersecurity Law Blog
小众软件
小众软件
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
AWS News Blog
AWS News Blog
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
I
InfoQ
Schneier on Security
Schneier on Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
The Exploit Database - CXSecurity.com
IT之家
IT之家
T
Threatpost
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
腾讯CDC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
News and Events Feed by Topic
L
LINUX DO - 最新话题
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
H
Heimdal Security Blog
S
SegmentFault 最新的问题

overreacted — A blog by Dan Abramov

There Are No Instances in atproto — overreacted Algebraic Effects for the Rest of Us — overreacted A Social Filesystem Hire Me in Japan — overreacted How to Fix Any Bug — overreacted Where It's at:// — overreacted Open Social A Lean Syntax Primer — overreacted Beyond Booleans — overreacted The Math Is Haunted — overreacted Suppressions of Suppressions — overreacted I'm Doing a Little Consulting — overreacted How Imports Work in RSC — overreacted RSC for LISP Developers — overreacted Progressive JSON — overreacted Why Does RSC Integrate with a Bundler? — overreacted One Roundtrip Per Navigation — overreacted Static as a Server — overreacted RSC for Astro Developers — overreacted Functional HTML — overreacted What Does "use client" Do? — overreacted Impossible Components JSX Over The Wire React for Two Computers The Two Reacts — overreacted A Chain Reaction — overreacted npm audit: Broken by Design — overreacted Before You memo() — overreacted The WET Codebase — overreacted Goodbye, Clean Code — overreacted My Decade in Review — overreacted What Are the React Team Principles? — overreacted On let vs const — overreacted What Is JavaScript Made Of? — overreacted How Does the Development Mode Work? — overreacted Preparing for a Tech Talk, Part 3: Content — overreacted Name It, and They Will Come — overreacted Writing Resilient Components — overreacted A Complete Guide to useEffect How Are Function Components Different from Classes? — overreacted Coping with Feedback — overreacted Fix Like No One’s Watching — overreacted Making setInterval Declarative with React Hooks — overreacted React as a UI Runtime Why Isn’t X a Hook? — overreacted The “Bug-O” Notation — overreacted Preparing for a Tech Talk, Part 2: What, Why, and How — overreacted The Elements of UI Engineering — overreacted Things I Don’t Know as of 2018 — overreacted Preparing for a Tech Talk, Part 1: Motivation — overreacted Why Do React Hooks Rely on Call Order? — overreacted Optimized for Change — overreacted How Does setState Know What to Do? — overreacted My Wishlist for Hot Reloading — overreacted Why Do React Elements Have a $$typeof Property? — overreacted How Does React Tell a Class from a Function? — overreacted Why Do We Write super(props)? — overreacted
Introducing RSC Explorer — overreacted
2025-12-19 · via overreacted — A blog by Dan Abramov

In the past few weeks, since the disclosure of the critical security vulnerability in React Server Components (RSC), there’s been a lot of interest in the RSC protocol.

The RSC protocol is the format in which React trees (and a superset of JSON) get serialized and deserialized by React. React provides both a writer and a reader for the RSC protocol, which are versioned and evolved in lockstep with each other.

Because the RSC protocol is an implementation detail of React, it is not explicitly documented outside the source code. The benefit of this approach is that React has a lot of leeway to improve the format and add new features and optimizations to it.

However, the downside is that even people who actively build apps with React Server Components often don’t have an intuition for how it works under the hood.

A few months ago, I wrote Progressive JSON to explain some of the ideas used by the RSC protocol. While you don’t “need” to know them to use RSC, I think it’s one of the cases where looking under the hood is actually quite fun and instructive.

I wish the circumstances around the increased interest now were different, but in any case, that interest inspired me to make a new little tool to show how it works.

I’m calling it RSC Explorer, and you can find it at https://rscexplorer.dev/.

Obviously, it’s open source.


“Show, don’t tell”, as they say. Well, there it is as an embed.

Let’s start with the Hello World:

Notice there’s a yellow highlighted line that says something cryptic. If you look closely, it’s <h1>Hello</h1> represented as a piece of JSON. This line is a part of the RSC stream from the server. That’s how React talks to itself over the network.

Now press the big yellow “step” button!

Notice how <h1>Hello</h1> now appears on the right. This is the JSX that the client reconstructs after reading this line. We’ve just seen a simple piece of JSX—the <h1>Hello</h1> tag—cross the network and get revived on the other side.

Well, not really “cross the network”.

One cool thing about RSC Explorer is that it’s a single-page app, i.e. it runs entirely in your browser (more precisely, the Server part runs in a worker). This is why, if you check the Network tab, you’ll see no requests. So in a sense it’s a simulation.

Nevertheless, RSC Explorer is built using exactly the same packages that React provides to read and write the RSC protocol, so every line of the output is real.


Async Component

Let’s try something slightly more interesting to see streaming in action.

Take this example and press the big yellow “step” button exactly two times:

(If you miscounted, press “restart” on the left, and then “step” two times again.)

Have a look at the upper right pane. You can see three chunks in the RSC protocol format (which, again, you don’t technically need to read—and which changes between versions). On the right, you see what Client React reconstructed so far.

Notice a “hole” in the middle of the streamed tree, visualized as a “Pending” pill.

By default, React would not show an inconsistent UI with “holes”. However, since you’ve declared a loading state with <Suspense>, a partially completed UI now can be displayed (notice how the <h1> is already visible but <Suspense> shows the fallback content because <SlowComponent /> has not streamed in yet).

Press the “step” button once again, and the “hole” will be filled.


Counter

So far, we’ve only sent data to the client; now let’s also send some code.

Let’s use a counter as the classic example.

Press the big yellow “step” button twice:

That’s just a good old counter, nothing too interesting here.

Or is there?

Have a look at the protocol payload. It’s a bit tricky to read, but notice that we’re not sending the string "Count: 0" or the <button>s, or any HTML. We’re sending <Counter initialCount={0} /> itself—the “virtual DOM”. It can, of course, be turned to HTML later, just like any JSX can, but it doesn’t have to be.

It’s like we’re returning React trees from API routes.

Notice how the Counter reference becomes ["client",[],"Counter"] in the RSC protocol, which says “grab the Counter export from the client module”. In a real framework, this would be done by the bundler, which is why RSC integrates with bundlers. If you’re familiar with webpack, this is similar to reading from the webpack require cache. (In fact, that’s how RSC Explorer implements that.)


Form Action

We’ve just seen the server referring to a piece of code exposed by the client.

Now let’s see the client referring to a piece of code exposed by the server.

Here, greet is a Server Action, exposed with 'use server' as an endpoint. It’s passed as a prop to the Client Form component that sees it as an async function.

Press the big yellow “step” button three times:

Now enter your name in the Preview pane and press “Greet”. The RSC Explorer debugger will “pause” again, showing we’ve hit the greet Server Action with a request. Press the yellow “step” button to see the response returned to the client.


Router Refresh

RSC is often taught with a framework, but that obscures what’s happening. For example, how does a framework refresh server content? How does a router work?

RSC Explorer shows frameworkless RSC. There’s no router.refresh—but you can implement your own refresh Server Action and a Router Component.

Press the “step” button repeatedly to get the whole initial UI on the screen:

Look at the ticking timer. Notice how the ColorTimer component from the Server passed a random color to the Timer component on the Client. Again, the Server has returned <Timer color="hsl(96, 70%, 85%)" /> (or such).

Now press the Refresh button right above the timer.

Without digging into the code, “step” through the server response and see what happens. You should see a continously ticking Timer receive new props from the server. Its background color will change but its state will be preserved!

In a sense, it’s like refetching HTML using something like htmx, except it’s a normal React “virtual DOM” update, so it doesn’t destroy state. It’s just receiving new props… from the server. Press “Refresh” a few times and step through it.

If you want to look how this works under the hood, scroll down both Server and Client parts. In short, the Client Router keeps a Promise to the server JSX, which is returned by renderPage(). Initially, renderPage() is called on the Server (for the first render output), and later, it is called from the Client (for refetches).

This technique, combined with URL matching and nesting, is pretty much how RSC frameworks handle routing. I think that’s a pretty cool example!


What Else?

I’ve made a few more examples for the curious folks:

And, of course, the infamous:

(As you would expect, this one only works on the vulnerable versions so you’d need to select 19.2.0 in the top right corner to actually get it to work.)

I’d love to see more cool RSC examples created by the community.

RSC Explorer lets you embed snippets on other pages (as I’ve done in this post) and create sharable links as long as the code itself is not bigger than the URL limit. The tool is entirely client-side and I intend to keep it that way for simplicity.

You’re more than welcome to browse its source code on Tangled or GitHub. This is a hobby project so I don’t promise anything specific but I hope it’s useful.

Thank you for checking it out!