React Server Components in Next.js 12
Tags: react, nextjs, webdev, programming
Published: 2022-01-10 21:44:08

**Written by [Chinwike Maduabuchi](https://blog.logrocket.com/author/chinwikemaduabuchi/)** ✏️

There have been continuous efforts to deliver a unanimous rendering solution for React apps. By December 2020, the React team had introduced the idea of React Server Components — abbreviated as “RSC” in this post — a feature for their upcoming version, React 18.

RSC is an experimental, opt-in feature that aims to cut out the work we usually give to the client by rendering everything, including the components, on the server. This approach produces zero bundle-sized components, consequently improving the load time of your web pages.

Vercel, the company behind Next.js, has been collaborating with the React team to roll out their latest version, Next.js 12, which integrates React 18 — RSC included — directly into the framework. [View the full list of Next.js 12 features](https://nextjs.org/blog/next-12).

## Prerequisites

For this tutorial, you'll need:

*   The latest version of Node.js
*   Basic knowledge of Next.js
*   React 18 installed in your project

_N.B.,_ _React 18 is still in alpha and_ _it_ _is not advisable to use in production just yet. Also, RSC won't be shipped with the first version of React 18_ _and is only available in certain frameworks — such as_ _Next.js_ _and_ _Hydrogen – under an experimental flag. This article should only serve as_ _a_ _guide as we look forward to a stable release._

Before we dive into RSC, let’s look at the previous prerendering solutions Next.js provided

## Taking a look back

Next.js has introduced several clever techniques for prerendering content, which include:

### Server-side rendering (SSR)

In server-side rendering, your application's data is fetched on the server, and HTML pages are generated for each route and sent to the user. When received, your user’s browser runs the client JavaScript code to make the generated HTML interactive — this is known as hydration.

This way, your user has content to see when they first land on your page, as opposed to serving a blank, white screen (_cringes internally –_ Skeletons, at least?) while external data is being fetched — which is the case in single-page React apps.

### Static site generation (SSG)

Traditional JavaScript-based websites as we know them are actually static sites. Here, the process of compiling and rendering a website is done at runtime, in the browser. Next.js improves upon this by compiling and rendering the website at build time.

The output is a bunch of static files, the HTML file, and assets like JavaScript and CSS. Similar to SSR, this method prerenders the website’s content for your user without depending on their internet speed to display something on screen.

Next.js also has other prerendering methods like

*   Automatic static optimization
*   [Incremental static regeneration](https://blog.logrocket.com/incremental-static-regeneration-with-next-js/)

Despite their success, SSR and SSG both have their setbacks. SSR websites are expensive to host, and SSG increases build time drastically as your application gets larger. [Read extensively](https://frontend-digest.com/client-side-rendering-vs-server-side-rendering-vs-static-site-generation-2a0702cbb08d?gi=8064817c7490) before choosing.

This is where RSC come to help. Let's get into the good stuff!

## What do React Server Components really do?

To put it simply, [React Server Components](https://blog.logrocket.com/what-you-need-to-know-about-react-server-components/) are components stored — and rendered — on the server. For this reason, they have two main advantages:

*   Direct access to the backend/database, which makes fetching data faster
*   They contribute nothing to the overall bundle size of your application. With this, you could even get away with importing large libraries for whatever function you may need them for:


```shell
npm install largest-package
```

However, because RSC aren't connected to the browser, they don't possess client-side interactivity and therefore can't manage state. This means hooks like `useState`, `useEffect`, and [some other Next.js APIs](https://nextjs.org/docs/advanced-features/react-18#unsupported-nextjs-apis) are not supported.

When coupled with client components and `Suspense`, React Server Components — created with a `.server.js` extension — can prerender content through HTTP streaming.

[HTTP streaming](https://www.pubnub.com/learn/glossary/what-is-http-streaming/) is a push-style data transfer technique that allows a web server to continuously send data to a client over a single HTTP connection that remains open indefinitely. It is an efficient method of transferring dynamic data between server and client.

Take this example:

```js
// my-rsc.server.js
import {db} from 'database'

// access backend 
const posts = db.posts.get(id);

return (
  <Page>
  <Suspense fallback={<Spinner/>}> 
      <BlogPosts posts={posts} />
    <Suspense/>
    <Footer />
  <Page/>
)
```

When this route is hit, the component renders everything on the page whilst displaying a fallback `Spinner` component for `BlogPosts` as it reaches out to the backend for data. The returned data is then streamed into `BlogPosts`, a client component.

Essentially, `Suspense` stops child components — that need extra computing — from blocking the entire application, thereby letting us beat the standard React waterfall architecture.

## Using React Server Components in Next.js 12

Next.js 12 can be installed by running the following command in your terminal:

```bash
npx create-next-app nextjs12-project
```

This creates a new Next.js app with its latest version.

Next, install the beta version of React 18 with the following command:

```bash
npm install next@latest react@beta react-dom@beta
```

This updates the React version to 18.

After the download is completed, proceed to edit the `next.config.js` file located in the root of your folder and add the following code:

```js
// next.config.js
module.exports = {
  experimental: {
    concurrentFeatures: true,
    serverComponents: true,
  },
}
```

This configuration enables both React Server Components and [Concurrent Mode](https://reactjs.org/docs/concurrent-mode-suspense.html#what-is-suspense-exactly).

Concurrent Mode enables React apps to stay responsive and adjust to the user’s device capabilities and network speed. This feature is where [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html#what-is-suspense-exactly) comes from.

Finally, create a `pages/_document.js` file with the following content:

```js
// _document.js
import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}
```

Now you're all set to use RSC in your application!

For this tutorial, rather than creating a project from scratch, I’ll be using the Hacker News project created by Vercel to explain how RSC are used in Next.js 12\. [Repository here](https://github.com/vercel/next-rsc-demo).

Open up your terminal, and clone the repository into your preferred directory:

```shell
Chinwike@Chinwike ~/Desktop/codebase/code
λ git clone https://github.com/vercel/next-rsc-demo.git
```

Open this project up in your text editor and let's examine the files. We’ll start at `pages/index.js`:

```js
// index.js
export default function Page() {
  return (
    <div className="container">
      {/* code ... */}
      <h1>React Server Components in Next.js</h1>
      {/* code ... */}
      <h2>React Server Components with Streaming</h2>
      <section>
        <a href="/rsc" target="_blank">
          RSC + HTTP Streaming
        </a>
      </section>
      {/* code ... */}
    </div>
  );
}
```

This index page contains links to other routes, each one displaying the same Hacker News app with different rendering methods.

Our focus will be on the RSC method in `pages/rsc.server.js`:

```js
// rsc.server.js
import { Suspense } from 'react'

// Shared Components
import Spinner from '../components/spinner'

// Server Components
import SystemInfo from '../components/server-info.server'

// Client Components
import Page from '../components/page.client'
import Story from '../components/story.client'
import Footer from '../components/footer.client'

// Utils
import fetchData from '../lib/fetch-data'
import { transform } from '../lib/get-item'
import useData from '../lib/use-data'

function StoryWithData({ id }) {
  const data = useData(`s-${id}`, () => fetchData(`item/${id}`).then(transform))
  return <Story {...data} />
}

function NewsWithData() {
  const storyIds = useData('top', () => fetchData('topstories'))
  return (
    <>
      {storyIds.slice(0, 30).map((id) => {
        return (
          <Suspense fallback={<Spinner />} key={id}>
            <StoryWithData id={id} />
          </Suspense>
        )
      })}
    </>
  )
}

export default function News() {
  return (
    <Page>
      <Suspense fallback={<Spinner />}>
        <NewsWithData />
      </Suspense>
      <Footer />
      <SystemInfo />
    </Page>
  )
}
```

This component features the blog page where the `NewsWithData` component — the component responsible for fetching posts — is wrapped in `Suspense`:

```js
<Suspense fallback={<Spinner />}>
  <NewsWithData />
</Suspense>
```

Here, `NewsWithData` makes use of two functions, `fetchData` and `useData`, to fetch the `storyIds` of all the posts from the API. It then maps out a `StoryWithData` component for each post.</span>

`StoryWithData` then uses the functions to fetch the content of each individual post, and stream it to the `Story` client component:

```js
// rsc.server.js 
function StoryWithData({ id }) {
  const data = useData(`s-${id}`, () => fetchData(`item/${id}`).then(transform))
 // Story is client component imported in a server component
  return <Story {...data} />
}
```

`Story.client.js` displays posts in the UI and adds client side interactivity to the application by implementing upvotes for each post.

```js

// story.client.js
// client components are regularreact components you're already familiar with

// client component can use state
import { useState } from 'react'

export default function Story({
  id,
  title,
  date,
  url,
  user,
  score,
  commentsCount,
}) {
  const { host } = url ? new URL(url) : { host: '#' }
  const [voted, setVoted] = useState(false)

  return (
    <div style={{ margin: '5px 0' }}>
      {/* code... */}
    </div>
  )
}
```

A live effect of RSC can be observed on the project when compared with the client-side rendering method in `pages/csr.js`.

On a throttled network, the page using CSR is evidently slower because the browser combines data fetching with the hydration of the components. [Watch the demo here](https://youtu.be/WlP2TB2ORL4?t=445).

## Conclusion

React Server Components are an amazing feature because they effectively handle rendering and let us build apps that span the server and client. Components can now load faster because most of the computing is shifted to the Server Components and away from the client. RSC’s official release is set to bring a change to the architecture of future React applications.

## References

As this is still a breaking topic, refer to the materials below for further information:

*   [Vercel blog post on React 18](https://nextjs.org/docs/advanced-features/react-18)
*   [Next.js at the Edge](https://youtu.be/WlP2TB2ORL4)
*   [Suspense architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
*   [React Conf 2021](https://conf.reactjs.org/)

---

## Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket](https://www2.logrocket.com/react-performance-monitoring). 

[![LogRocket Dashboard Free Trial Banner](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://www2.logrocket.com/react-performance-monitoring)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.