Since its introduction in 2020, React Server Components (RSC) has sparked heated discussions in the frontend world. Next.js 13 made RSC the default option last year, reigniting the interest in this technology.
However, based on what I have heard, adoption for production usage has not been as widespread as anticipated. At a recent meet-up, some people expressed their opinion that RSC is an unconventional solution that introduces more challenges than it resolves. Instead, they believe that Remix has already successfully addressed those issues.
As a developer who has experienced the simplicity of Remix but hasn't used RSC, I can't help but wonder if I still need RSC at all.
What Remix says
Simply search “remix react server components” in Google, and the top result I see is the below post written by the Remix co-founder Ryan Florence:
React Server Components and Remix
This is a great post that not only provides insight behind the scenes but also includes some great live demos and source code. Although this was written before RSC was officially supported by Next.js 13, it appears to be up-to-date based on my understanding(please correct me if I'm wrong). After reading it, it reinforces what I heard at the meet-up:
If I already have Remix, RSC may not be necessary.
The reason is that “Remix can take full advantage of RSC”. The author not only illustrated it through the demo but also conducted real-life testing:
I messed around with these two demos for several days: loading them from my phone while on the freeway (not driving, ofc, but wishing I could drive to Laksa King), waiting for my kids to get out of school on that hill where the cell connections are spotty, and even inside a church building where almost no cellular waves get through.
What a down-to-earth attitude! I followed him on Twitter simply because of this. 😁
This could have been the end of the story several years ago. However, the internet has taught me the importance of considering different points of view to achieve independent thought:
Embrace Dissent: Finding Value in Opposite Views
JS for ZenStack ・ Jul 4 '23
While I agree with everything the author has stated, I believe it is important to consider the different views of the different camps.
What RSC says
One more valuable lesson I've acquired is that when exploring new technology, the most reliable starting point is always the official documentation. In this case, the sole official document for the technology is the RFC available on GitHub:
As per the prerequisites mentioned at the beginning of the RFC, I also watched the following video:
Subsequently, I started to comprehend the motivation and trade-offs of the RSC, as well as why many people don't buy-in.
RSC introduces a new mental model of thinking about your whole web application
Personally, I feel this is the most important and valuable(arguably) thing RSC brings to us. In the new mental model, your whole application is componentized:
You can now achieve the colocation ( what changes together should stay together) at the component level. At the same time, it allows for composability throughout the entire application, rather than just for the separated frontend. What I find most appealing is that, if done it correctly, the same component can be both rendered on the client and server as needed.
As a result, performance benefits like Zero-Bundle-Size and No Client-Server Waterfalls naturally follow as consequences.
Why people don’t buy-in
Since it’s a new mental model, it needs time and practice to grasp it. It is definitely hard to keep the entire tree of the application in your head all at once, particularly when differentiating between client and server components. But isn’t it the same as when React was first introduced with JSX syntax?
Why people prefer Remix
It also explains why people think Remix is intuitive and easier to understand. Take the example that Dan uses in the video:
function ArtistPage({ artistId }) {
const stuff = fetchAllTheStuffJustInCase();
return (
<AristDetails details={stuff.details} artistId={artistId}>
<TopTrackers topTracks={stuff.topTracks} artistId={artistId} />
<Discography discography={stuff.discography} artistId={artistId} />
</AristDetails>
);
}
Most developers are so used to this fetch and render pattern. Essentially, it follows the classical API-first pattern, where you plan the data to be fetched from the server at the router layer, retrieve that data, and then pass it down as props to the child components throughout the application.
To make it server render in Remix, all you need to do is just simply move the first line to the loader
function:
export async function loader({ request }) {
return fetchAllTheStuffJustInCase();
}
However, as Dan specified in the video, it’s a kind of compromise for maintenance:
You might not think so probably because your current mental model works better this way. However, according to the colocation principle mentioned above, or just the more abstract low coupling and high cohesion principle, each component should be responsible for its own data. So, the code is better written this way:
function ArtistPage({ artistId }) {
return (
<AristDetails artistId={artistId}>
<TopTrackers artistId={artistId} />
<Discography artistId={artistId} />
</AristDetails>
);
}
function ArtistDetail({artistId, children}){
const details = fetchDetails(artistId);
// ...
}
That’s exactly what RSC offers for us without compromising user experience or performance.
Finally, Let's not forget that React was originally designed with a client-centric focus. Finding a unified solution without breaking anything existing was a distinct challenge faced and resolved by the React team. As a result, we can now incrementally convert our existing codebase, component by component, to enjoy its benefits. Respect for the React team! 👏
What Remix talks with RSC
After seeing the point of view from both camps, it is interesting and beneficial to observe the discussion between them:
The video is quite long, so I'll leave it to you. I'm looking forward to seeing Remix adopt RSC someday.
Speaking of mental models, the ZenStack open-source toolkit we're building introduces a new one for building your entire backend. It uses the schema file as the single source of truth for your core business logic and leverages code generation to automatically create APIs and front-end queries. Therefore, once the schema is complete, the backend is nearly finished.