React Server Components Deep Dive
TL;DR
- 
Server Components run entirely on the server. That's why they can directly access databases or backend logic inside the component. React renders the component on the server and sends static HTML to the browser — the client never sees the actual component code.
 - 
Tradeoffs: No
useState,useEffect, or DOM APIs (they’re static). - 
The new paradigm: All components are server components by default. To make a client component, add
"use client"at the top of the file. It creates a client boundary, and all its children become client components. 
To understand why server components are created, you need to first understand how React was rendered.
Client-side rendering (CSR)
Back when create-react-app still existed, React was client-side rendered.
When we visit a webpage made by a React app, these happen:
The CSR flow
- The browser sends a request to the server.
 - The server returns two things:
- An almost empty HTML file with a script tag linking to a bundle.js file.
 - A gigantic bundle file that contains all the JavaScript of the app.
 
 
Something like this:
<!DOCTYPE html>
<html>
  <body>
    <div id="root"></div>
    <script src="/static/js/bundle.js"></script>
  </body>
</html>
- The browser parses the JavaScript file to create the initial UI. But the data that you need to fetch from the server is not there yet. These components are most likely in the loading state.
 - Browser fetches those from the servers.
 - Finally, with all the resources present, a web page is rendered.
 

We call this client-side rendering (CSR)
Problems
The problem with this is the page load speed. It takes time to parse the JavaScript in the client to create a meaningful UI. Before that, the user will be staring at an empty white screen and is very likely to already leave the website to continue doom scrolling.
Plus, it’s not good for SEO.
So people came up with another strategy.
Server-side rendering (SSR)
See, in this process, there are actually two main parts.


First is to create DOM nodes and the UI. Second is adding interactivity, like event handlers and states. What if we separate them?
The SSR flow
- Instead of creating the UI in the browser, we first do it on the server, then send the static UI back.
 - The browser parses the JavaScript file and adds interactivity (event handlers, states) to the prerendered HTML. This process is called hydration.
 - The server data are still not there yet. So we still need to get it from other servers.
 - The final content is rendered.
 

Problems
This process is slightly better because users see a richer UI sooner. Plus, you can download less JavaScript.
But if you look at the graph and are a little more critical of why things are done this way.
You might wonder, since we create the UI and query the database on the server, why can't we do them together? And you can do fewer network requests.

That wasn't possible with the previous React components.
So they created the server component.
What is React Server Components (RSC)
Server components are created entirely in the server.
Because of that, you can do server operations in a React Server component, like fetching data from a database, or accessing the file system.
export default async function Page() {
  const users = await getUsersFromDB(); // This function runs on the server
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
Which is absolutely wild. Before this, you had to maybe do a fetch in useEffect and then create an API endpoint in the backend to handle these kinds of requests. But with server components, you can skip these steps.
import { useState, useEffect } from "react";
function UserList() {
  const [users, setUsers] = useState([]);
  useEffect(() => {
    async function fetchUsers() {
      const response = await fetch("/api/users");
      const data = await response.json();
      setUsers(data);
    }
    fetchUsers();
  }, []);
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
Server:
export default async function handler(req, res) {
  const users = await getUsersFromDB(); // This function runs on the server
  res.status(200).json(users);
}
Under the hood, React will run the database query, use the data to create a static HTML file, and send it to the browser.
The client never sees the component, just the static HTML.
Limitations of server components
But because the component is rendered on the server, it can't use any React hooks like useState or useEffect. It also can't access any browser APIs like the DOM or local storage.
For that, we still need client components.
Server component vs client component
Now we have two kinds of components:
- The original component we are using that are rendered in the browser, which is called client component
 - This server component
 
Here is a table summarizing the differences between React Server Components and Client Components:
| Server Components (SC) | Client Components (CC) | |
|---|---|---|
| Execution Environment | Rendered on the server only | Rendered in both the client & the server | 
| Rerender | Rendered once per request | Re-rendered as necessary | 
| JavaScript Bundle | Not included in client bundle, reduces bundle size | Included in client bundle, increases bundle size | 
| Access to React Hooks | No | Yes | 
| Access to Browser APIs | No | Yes | 
| async/await component | Yes | No | 
| Interactivity | Static | Fully interactive | 
When to use server components
Use server components when you want a faster page load, reduced JavaScript bundle size and SEO. Use client components when you can't use a server components, like adding interactivity or event handlers to the UI.
The new paradigm
With these two components in mind, React has a completely new paradigm, which is called RSC (aka react server component, I know it's a little bit confusing but I didn't come up with the name).
Under this new paradigm, every React component is a server component by default, unless you specify it to be a client component with a "use client" directive.
"use client";
function Page() {
  const [text, setText] = useState("lorem");
  return <p>{text}</p>;
}
When you make a component a client component, all its children will become client components. We call this the client boundary.

Are React server components worth it?
React server components completely change the way we write React apps. If you come from previous versions, the extra complexity doesn't seem to be worth it at first. But with the benefit of reduced bundle size, better performance and simplified data fetching, it's definitely worth a try. At least, I can't imagine going back to the old way of doing things.
Get the written notes delivered to your email inbox to learn something new about react one at a time.