Exploring “Data Fetching with React Server Components” with Next.js
Tags: nextjs, react
Published: 2024-04-26 07:01:07


This is a brief takeaway of what I learned in this YouTube video titled “Data Fetching with Server Components.” I also tried Next.js to see what features we already have.
- [Motivation](#motivation)
  - [Issue](#issue)
  - [React Team’s Solution: Put data fetching logic on the server](#react-teams-solution-put-data-fetching-logic-on-the-server)
- [Server Side Rendering vs React Server Components](#server-side-rendering-vs-react-server-components)
  - [Server Side Rendering (SSR)](#server-side-rendering-ssr)
  - [React Server Components](#react-server-components)
- [Server Component Features](#server-component-features)
  - [Zero Effect on the Bundle Size](#zero-effect-on-the-bundle-size)
  - [Direct Access to the Backend Resources](#direct-access-to-the-backend-resources)
  - [Automatic Code Splitting](#automatic-code-splitting)
  - [Server Components require users’ decision](#server-components-require-users-decision)
  - [Server Components provide modern UX with a server-driven mental model](#server-components-provide-modern-ux-with-a-server-driven-mental-model)
- [Ref](#ref)


## Motivation

### Issue

The React team wants to create apps with good user experience, cheap maintenance, and fast performance co-existing.

In general, having two of them in one project is comparatively more straightforward, but having all of them is pretty challenging.

**Example: Good user experience and fast performance**

With the code snippet, the app can render all components simultaneously and doesn’t suffer from the request waterfall, as it gets all data in one request. However, this code sacrifices the cheap maintenance because each component's API responses are coupled.
```javascript
    function ArtistPage({artistId}){
    const stuff = fetchAllTheStuffJustInCase()
     return (
      <ArtistDetails artistId={artistId} details={stuff.details} />
       <TopTracks artistId={artistId} details={stuff.topTracks} />
       <Discography artistId={artistId} details={stuff.discography} />
      </ArtistDetails>
     )
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=4m12s
```
🗒️ This code reminds me of the Easier to Change (ETC) principle provided in [*The Pragmatic Programmer](https://www.amazon.ca/Pragmatic-Programmer-journey-mastery-Anniversary/dp/0135957052/ref=sr_1_1?dib=eyJ2IjoiMSJ9.84Xun4zePRzxcYJXHbNXB7dVm4lTzy9-7zrFUNgNQC8ZHty2sHX0n1IsAHY91IBc1bdPT4gNcMDDvpCGNBFy8ACvEMWwwO2NpQIt3nNCUaePhJevHoblIHrPC0wdt93H8FBHZG831b7lpaU1TAUTkpo5ZIv3B6QdxWZ4cK9NtdKEvbDE8TQuUllAA3XORSC3XChN_6O6ctCfYW6CORYlIidUMhzEe_ef0BFZ9ambMqTHSmRv5GTC_JsVce7g2gR7cSTnlk8-DWYf5Qhry9nSpj6byyhQhG0Miq_DXQmn6zs.Kat3fEXI70AhmdZguQ2hKqnCeNj1jjMHU06GPtLRw9I&dib_tag=se&hvadid=667095410527&hvdev=c&hvlocphy=9001551&hvnetw=g&hvqmt=e&hvrand=18375279749113656674&hvtargid=kwd-302199567278&hydadcr=23310_13656858&keywords=the+pragmatic+programmer&qid=1712210601&sr=8-1)*. According to the book, “Good design is easier to change than bad design.” It also says, “Decoupled code is easier to change.”

The code below can reduce the maintenance cost but causes a so-called [request waterfall](https://tanstack.com/query/latest/docs/framework/react/guides/request-waterfalls#what-is-a-request-waterfall), sacrificing the performance speed. In addition, the app no longer renders all components simultaneously, and now they all depend on each request order.
```javascript
    // Ideal way
    function ArtistPage({artistId}){
     return (
      <ArtistDetails artistId={artistId} />
       <TopTracks artistId={artistId} />
       <Discography artistId={artistId} />
      </ArtistDetails>
     )
    }
    
    function ArtistDetails({artistId}) {
     const details = fetchDetails(artistId)
     // ...
    }
    
    function TopTracks({artistId}) {
     const topTracks = fetchTocpTracks(artistId)
     // ...
    }
    
    function Discography({artistId}) {
     const discography = fetchDiscograhy(artistId)
     // ...
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=5m20s
```
🗒 I like this part because I can sense the strong eagerness to break through what we call impossible.

### React Team’s Solution: Put data fetching logic on the server

![Before](https://cdn-images-1.medium.com/max/2388/1*ZuI-9uE5g6HKDvkjDvuw0w.png)

![After](https://cdn-images-1.medium.com/max/2356/1*b6aMoNtgfDWtrp6_IbgF-g.png)

## Server Side Rendering vs React Server Components

### Server Side Rendering (SSR)

SSR is a technique that serves an initial HTML when the first page loads. Once the first HTML is loaded, it is required to download/parse/execute Client Components.

![A very simplified SSR image](https://cdn-images-1.medium.com/max/3096/1*IY2oJ3sJRv7JJldnrDomVg.png)

### React Server Components

React Server Components are not interactive with the client side. Client Components always take responsibility for interacting with users and trigger re-fetch Server Components trees corresponding to the user’s actions. Notably, the client-side state is preserved when the re-fetch. We can do this with Server Components because Server Components don’t render to HTML, but they render into a special format.

![](https://cdn-images-1.medium.com/max/3368/1*zCAyYNG8IP61MmewTywwOA.png)

Here is an example of where the client states are preserved when the re-fetch with Next.js. The search input appears only when the search input state is true, and the to-do list is filtered by the filter query controlled on the server side.

![Demo](https://miro.medium.com/v2/resize:fit:800/1*RUpSTMWbf24kwwsrBRldWA.gif)

cf) Here is how Next.js explains the interaction between Server Components and Client Components. Next.js calls the special format React Server Component Payload.
[**React Foundations: Server and Client Components | Next.js**](https://nextjs.org/learn/react-foundations/server-and-client-components)

## Server Component Features

### Zero Effect on the Bundle Size

We can reduce dependencies downloaded to the client by moving some heavy dependencies components to the server.

![](https://cdn-images-1.medium.com/max/2568/1*1vLVf4y3BW7uk1hk5PYLUg.png)

⚠️ Not exactly HTML files (as Server Components render into a special format), but I mention only HTML here for the sake of ease.

### Direct Access to the Backend Resources

Because Server Components are rendered on the server side, they can access the server-side resources directly.
```javascript
    // Example 1
    
    import { resolve, join } from 'path';
    import { readdir, readFile } from 'react-fs';
    import marked from 'marked';
    
    const folder = resolve(__dirname + '/../posts');
    
    function Blog() {
     return readdir(folder).map(name => 
      <article key={name}>
       {/* Access the file system directly without creating any API */}
       {marked(readFile(join(folder, file), 'utf8'))} 
      </articke>
     );
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=37m57s
```
```javascript
    // Example 2
    
    import marked from 'marked';
    import { db } from './db';
    
    function Blog() {
     return db.posts.getAll().map(post => 
      <article key={post.id}>
       {marked(post.html)}
      </article>
     )
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=38m05s
```
### Automatic Code Splitting

Server components allow for the loading of only the required code. This means that server components are not downloaded to the client, and even client components that are not being used do not need to be downloaded.
```javascript
    // Example
    
    import EditToobar from './EditToolbar.client';
    
    function Comment({ comment, currentUser }) {
     const canEdit = (
      currentUser.isAdmin ||
      currentUser.id === comment.author.id
     );
     return (
      <Box>
      {/* EditToonar is downloaded only when canEdit === true */}
       {canEdit && <EditToolbar />}
       <p>{comment.text}</p>
      </Box>
     )
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=41m25s
```
This is questionable with Next.js, as I found client components not rendered in the initial render when I inspected the source after running npm run build.

![Demo of experimental code](https://cdn-images-1.medium.com/max/5624/1*4LXayrkefemDErvyrH-V9g.gif)

### Server Components require users’ decision

Server Components let you decide the Client and Server Components tradeoff for every concrete use case.
[**Rendering: Composition Patterns | Next.js**](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#when-to-use-server-and-client-components)

🗒️ I think this is a double-edged sword feature as we have to understand the ins and outs of React, including both Server Components and Client Components (and Shared Components), to decide which to use in each case. In other words, it all depends on developers to make the most of the server components or to make them waste treasures.

### Server Components provide modern UX with a server-driven mental model

Server Components enable developers to create modern and app-like user interfaces in an old-school way.
```javascript
    // Example
    
    import SearchInput from './SearchInput.client';
    
    function SearchResults({searchText}) {
     const results = fetch('/search?q' + searchText).json();
     return (
      <>
       {/*This component triggers re-fetch of the server tree*/}
       <SearchInput /> 
       <ul>
        {results.map(result => 
         <li key={result.id}>{result.text}</li>
        )}
       </ul>
      </>
     )
    }
    
    // https://youtu.be/TQQPAU21ZUw&t=44m45s
```
## Ref
[**Introducing Zero-Bundle-Size React Server Components - React**](https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components)
[**rfcs/text/0188-server-components.md at main · reactjs/rfcs**](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#rfc-react-server-components)

The whole demo code is available [here](https://github.com/Lada496/next-experiment).
[original article](https://medium.com/@lada496/exploring-data-fetching-with-react-server-components-with-next-js-54c96f77ea99)