React Server Components

Shivam Jha

Shivam Jha / December 24, 2022

5 min read

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 ?