---
sidebar_position: 9
tags: [Web, React, Server Components]
---

# Server Components

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

Give React a chunk of code that it runs exclusively on the server,
to do the database query to eliminate redundant network requests,
polish FCP and LCP, and improve SEO:

[![React Server Components](./figures/rsc-network.png)](https://www.joshwcomeau.com/react/server-components)

Each meta-framework came up with its own approach to achieve such target.
Next.js has one approach, Gatsby has another, Remix has yet another.
It hasn't been standardized.

<Tabs>
<TabItem value="next" label="Next">

```tsx
import type { PageProps } from '@/types'
// pages/index.js
import ParentComponent from '../components/parent-component'

export default function Page({ data }: PageProps) {
  return <ParentComponent data={data} />
}

export async function getServerSideProps() {
  const response = await fetch('https://api.github.com/repos/vercel/next.js')
  const data = await response.json()

  return { props: { data } }
}
```

</TabItem>
<TabItem value="remix" label="Remix">

```tsx
import { json } from '@remix-run/node'
// app/routes/_index.jsx
import { useLoaderData } from '@remix-run/react'
import ParentComponent from '../components/parent-component'

export default function Page() {
  const { data } = useLoaderData()

  return <ParentComponent data={data} />
}

export async function loader() {
  const response = await fetch('https://api.github.com/repos/remix-run/remix')
  const data = await response.json()

  return json({
    data,
  })
}
```

</TabItem>
<TabItem value="gatsby" label="Gatsby">

```tsx
import type { PageProps } from '@/types'
// src/pages/index.js
import ParentComponent from '../components/parent-component'

export default function Page({ data }: PageProps) {
  return <ParentComponent data={data} />
}

export async function getServerData() {
  const response = await fetch('https://api.github.com/repos/gatsbyjs/gatsby')
  const data = await response.json()

  return { props: { data } }
}
```

</TabItem>
</Tabs>

For years, the React team has been quietly tinkering on this problem,
trying to come up with an official way to solve this problem.
Their solution is called `React Server Components`.

Server Components never re-render.
They run once on the server to generate the UI.
The rendered value is sent to the client and locked in place.
As far as React is concerned, this output is immutable, and will never change:

```tsx
import db from 'imaginary-db'

export default async function Homepage() {
  const link = db.connect('localhost', 'root', 'pass0w0rd')
  const data = await db.query(link, 'SELECT * FROM products')

  return (
    <div>
      <h1>Trending Products</h1>
      {data.map(item => (
        <article key={item.id}>
          <h2>{item.title}</h2>
          <p>{item.description}</p>
        </article>
      ))}
    </div>
  )
}
```

Code for Server Components isn't included in the JS bundle.
We send the virtual representation (along the rendered value)
that was generated by the server.
When React loads on the client,
it re-uses that description instead of re-generating it:

[![Virtual DOM for React Server Components](./figures/rsc-virtual-dom.png)](https://demystifying-rsc.vercel.app/static-content/2)

```html
<!doctype html>
<html>
  <body>
    <div>
      <h1>Trending Products</h1>
      <article>
        <h2>Product 1</h2>
        <p>Description 1</p>
      </article>
      <article>
        <h2>Product 2</h2>
        <p>Description 2</p>
      </article>
    </div>

    <script src="/static/js/bundle.js"></script>
    <script>
      self.__next['$Homepage-1'] = {
        type: 'div',
        props: null,
        children: [
          {
            type: 'h1',
            props: null,
            children: ['Trending Products'],
          },
          {
            type: 'article',
            props: { key: 1 },
            children: [
              { type: 'h2', props: null, children: ['Product 1'] },
              { type: 'p', props: null, children: ['Description 1'] },
            ],
          },
          {
            type: 'article',
            props: { key: 2 },
            children: [
              { type: 'h2', props: null, children: ['Product 2'] },
              { type: 'p', props: null, children: ['Description 2'] },
            ],
          },
        ],
      }
    </script>
  </body>
</html>
```

[RSCs](https://www.smashingmagazine.com/2024/05/forensics-react-server-components):

- Addresses SEO and loading time issues in CSR.
- Improves SSR by reducing server load.

## Directives

`'use client'` [directive](https://demystifying-rsc.vercel.app/client-components/no-ssr):

- It tells the bundler to output this code as a separate file with its own url
  so it can be loaded lazily in the browser.
- It tells the compiler when this code is needed,
  it should add code to load the js file for this component.
- It tells RSC that the Virtual DOM it generates
  should contain a placeholder reference to this Client Component,
  rather than the component's html output.
- It still runs on the server, `'use client'` does not disable SSR.

![Use Client Directive](./figures/rsc-use-client.png 'Use Client Directive')

## Composition

Server Components and Client Components are [different](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#when-to-use-server-and-client-components):

| Features                    | Server | Client |
| --------------------------- | :----: | :----: |
| Backend Resources           |   o    |   x    |
| Server Sensitive Data       |   o    |   x    |
| Event Handlers              |   x    |   o    |
| State and Lifecycle Effects |   x    |   o    |
| Browser-only APIs           |   x    |   o    |

Client Boundaries:

- All of components within client boundary are implicitly converted to Client Components.
  (Once the component became client-side, its nested components are client-side too).
- Client Components can only import other Client Components.
- Moving Client Components down the tree, to reduce Client JavaScript bundle size.

[![Client Boundaries](./figures/rsc-client-boundaries.png)](https://www.joshwcomeau.com/react/server-components/#boundaries-6)

You can't import Server Components inside Client Components directly,
but can passing Server Components to Client Components as `Props`:

```tsx
// app/ColorProvider.tsx
'use client'

import { DARK_COLORS, LIGHT_COLORS } from '@/constants'

export default function ColorProvider({
  children,
}: {
  children: React.ReactNode
}) {
  const [colorTheme, setColorTheme] = React.useState('light')
  const colorVariables = colorTheme === 'light' ? LIGHT_COLORS : DARK_COLORS

  return <body style={colorVariables}>{children}</body>
}
```

```tsx
// app/page.tsx
import ColorProvider from './ColorProvider'
import ServerComponent from './ServerComponent'

// Pages in Next.js are Server Components by default
export default function Page() {
  return (
    <ColorProvider>
      <ServerComponent />
    </ColorProvider>
  )
}
```

[3rd party Client Components](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#advice-for-library-authors):

- Wrap them into a wrapper component using `'use client'`.
- Library authors [add `'use client'` to components](https://github.com/ant-design/antd-tools/blob/050a91cfeaba87c2892bf19d721665a3770ebde0/lib/gulpfile.js#L197-L213).

## Server Actions

Server actions are [wrapper around `POST` requests](https://www.developerway.com/posts/server-actions-for-data-fetching),
meant for mutations, e.g. form submissions, database writes, state changes.

:::caution

Server actions are not designed for data fetching:

- Frameworks implementing server functions typically process one action at a time.
- No caching via HTTP headers.
- No request memoization.

:::

## References

- React Server Components in [Next.js](https://vercel.com/blog/understanding-react-server-components).
- React Server Components [introduction](https://www.joshwcomeau.com/react/server-components).
- Demystifying React Server Components [series](https://demystifying-rsc.vercel.app).
- React Server Components [devtools](https://www.alvar.dev/blog/creating-devtools-for-react-server-components).
