Reactive Stack

How Server Components Data Fetching Could Be Working (Still Prototype)

Cover Image for How Server Components Data Fetching Could Be Working (Still Prototype)
Benoit Tremblay
Benoit Tremblay

React server components are non-interactive components that are meant to be run only on the server rather than the client. You cannot use useState, useEffect or DOM events like a click or a scroll because it is not going to be running in the browser. It will only be used on the server to output HTML.

One interesting thing that you will be able to do on server components is fetching data and only render that component when the data is available. Because you are on the server, you can afford to fetch the data and wait for that to be available before the first paint. Say goodbye to loading state when loading a page, the data will be available from the get go!

Here is an example of how you could be fetching data from an API.

import { fetch } from 'react-fetch';
import MenuCategory from './MenuCategory';

export default function MenuCategoryList() {
  const categories = fetch('http://my.api/categories').json();

  return categories.length > 0 ? (
    categories.map((category) => <MenuCategory category={category} />)
  ) : (
    <h3>Category empty</h3>
  );
}

In this example, the fetch is acting just like the regular browser fetch except that it is not asynchronous. My first question was how the hell is this even possible? It is running on Node.js and it is single thread. There is no way it could be blocking here. I had to dig into the implementation of the demo to understand a little bit more.

The Magic Behind The Scene: Suspsense!

React Suspense is the magic behind the scenes for making the data fetching synchronous. As long as the data are not done fetching, it will suspend the rendering of that component and retry to render it only when the data are now available. It is synchronous because the component is not rendered once, it is actually rendered twice. The first time will trigger the request and suspend (throw a promise). The second renders will happen when the fetching is done and you it is able to read the data and then show the component. Prettier clever considering we cannot do something asynchronous within a React component because the result of the render would already be returned.

WARNING: This is only based on a demo prototype

Most of what I'm talking about is from the React RFC as well as the demo prototype. It will most likely change. All of this are just speculation for the fun of exploring the ideas. Nothing is final nor released yet and I have no insider knowledge on how this is actually built.

Current Data Source

The React team has built three different data source as example on how to fetch data:

  • react-fs: Get data from the files and folders.
  • react-pg: Query a Postgres database directly. You don't even need to expose an API if you're using this one.
  • react-fetch: Call an API using the same syntax as the well-known browser fetch. Very useful if your system is using microservices. This is the only one that can work both on the server as well as client components.

You will also be able to build your own.

Writing Your Data Source

Let's explore the required step to build a data source according to the examples we have.

1. Get the cache for your type

You have to provide a factory function that will generate an empty map. This is going to be used as a cache by your implementation as well as by React Suspense to know when the fetching is done. The map will be created once and reuse the instance after that.

2. Check if the request is in the cache

Now that we have our cache, let's check if we already fetched the same data using a unique key. If it did, we can skip the rest and return the same previous data we had or throw if it is not yet resolved.

3. Add a record to the cache in pending state and suspend

This is the part we create a record object to keep track of the state of the request. We create a record with a pending status as well as the promise as value. Then, we suspend the flow by throwing that promise. This is how the method can be synchronous. It will get render at least twice if the data is not yet fetched.

4. When done fetching, update the record

When the fetching has been done with a success or failure, you update the status of the record (resolved or rejected). Your component will now be able to be rendered and will no longer wait.

If you want to read an actual implementation, go start with fs.readFile in react-fs.

Go Read the RFC

Sorry for being a broken record, but keep in mind this is based on the RFC and prototype. If you want to learn more about React Server Components, I encourage you to read the RFC. It is surprisingly easy to read compared to what a RFC normally is and you will learn more about the future of React!

More Trends?

Do you want to know more about the upcoming trends in 2021? Read my Top 5 Trends in 2021 for React Developers.

Want More Content About React.js?
Subscribe to Our Newsletter

* indicates required

We will never spam you.