Introduction
React Server Components run only on the server. The "only" part is important here. They are designed to leverage your servers better, as described in this rfc published back around October 2022. You can think of them as Normal React Components, but that they only gets executed on server, and then they are sent to the client.
Normal React Components (when Server Rendered) are first "rendered" on the server into HTML and sent to the client (browser). Later, React adds interactivity to them (attaching event listeners to DOM elements). This process is called Hydration
In case of React Server Components, the execution process happens at the server. So, you can think like "hydration" of React Server Components happen only in the Server, the components get rendered into HTML and are sent to the client. And since, they are executed on the server, there is no need for Hydration on the client, and hence they ship without increasing your bundle side
Here is a very good visual representation for you to understand the difference between Server Side Rendering and React Server Components (Credit: @shuding_):
Server Side Rendering
React Server Components
When I should use React Server Components ?
- One of the main use cases of RSC(s) is that you can use a large-size library (like for markdown or for date formatting, etc.) in your server, while having zero impact on your bundle size.
import Foo from 'my-heavy-library'
// Component that consumes Foo
function Bar() {
// ...Do something
}
// Same library, but with Server Components, zero bundle size
import Foo from 'my-heavy-library'
// Same component
function Bar() {
// ...Do something
}
- At other times, you might want to use
env
variables to access some keys, or do data fetching from your DB. You can do all that with RSC, without leaking anything in the browser source. (Well, you could do the same thing with SSR). As a general rule of thumb, if you want to use Server Resources directly, and don't want them to leak on the client, you can fetch data inside Server Components.
async function getData() {
const res = await fetch('https://api.example.com/...', {
key: process.env.MY_SECRET_KEY,
})
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
// Recommendation: handle errors
if (!res.ok) {
// ...
}
return res.json()
}
// Server Component
export default async function Page() {
const data = await getData()
return <main></main>
}
- Using RSC, you can make sure that there are no Client Network Waterfalls. (The issue when JavaScript needs to be downloaded before a component can even start fetching data - If that component is nested deep in the component tree and parent component needs some data, then data fetching cannot even start before the child is rendered if traditional client-side rendering is used). Some libraries like Tanstack Query and React Router makes this easier by prefetching data. But still, in case of client-only rendering, you cannot fetch data before your JavaScript is downloaded.
When not to use Server Components ?
Server components cannot have any interactivity (
onClick
,onScroll
, etc.) and can only be used for generating plain HTML stuff. For interactivity, you have to use what are now called Client Components.Server Components cannot have state (
useState
) or use Side Effects (useEffect
, etc). (Since the cannot have interactivity). Or custom hooks that depend on combination of state and effects.Since they run on server, and server only, they cannot use browser APIs (like
localStorage
, etc.)
For a full comparison, check out Next.js docs for app
directory
Okay, how do I use them in my app ?
Back in October 2022, Next 13 was released with support for Server Components. You can check out beta Next.js Docs if you want to try out RSC in your existing Next.js Applications. It is still experimental (at the time of writing this blog)
In case of Remix, seems they are not transitioning yet to RSC. Checkout this blog explaining React Server Components and Remix. Btw, Remix already solved the problems that RSC solves. With Remix Loaders, you can fetch data in the Server, and this will be run only on the server, without being shipped to the client. Components server-rendered by Remix can have interactivity (in terms of state and side-effects). Also, Remix comes with built-in mechanism for de-duping requests, handling race conditions & fetch cancellations
Top comments (3)
Very concise. Thank you for this piece.
Thanks! Glad you liked it
How to share data between server/client components without prop drilling? Is context working fine between server and client components?