Categories
Tech

React Server Components

You know when you load a site, and random parts of the page seem to take much longer to load than others? In a React site, this is often because one component sits within another. In order to load the child component, whatever data that is needed to render the parent is fetched first, thus causing a delay in loading the child.

function MyProfile({person}) {
 return(
  <MyProfileTheme theme={person.theme} > 
    <MyFace name={person.name} />
    <MyInfo info={person.info} />
  </MyProfileTheme>
)
}

However, when it comes to addressing this issue, there are some considerations. If the developer wants the code to be easily maintainable, they would want the data fetching for each component to be contained within the component itself, as opposed to being coupled to the root component.

export function MyProfileTheme({theme}) {

 const individualTheme = fetchMyTheme() 
 return <IndividualTheme/>

}

But, if components are nested within each other, we get a cascade of fetch requests, as mentioned previously, known as waterfalling. For each request, the client has to make a fetch request, wait for the server to return the data, and then as soon as that is complete, make another. This can definitely affect performance!

Last year, the React team at Meta began developing the concept of moving React components into the server, so that the client only makes one request to the server.

https://dev.to/nas5w/what-is-the-difference-between-server-side-rendering-ssr-and-react-server-components-5339

A new type of tag is added to a file name to indicate to React that the file is to be rendered on the server.

App.server.js

(as opposed to Root.client.js)

An important benefit of writing components in this way is that if hefty libraries or dependencies are utilized in a component which is rendered on the server, these dependencies do not have to be rendered by the client.

import { ClunkyDependency} from "somewhere"

function MyProfile({person}) {

const importantThing = ClunkyDependency()

 return(
  <MyProfileTheme theme={person.theme} > 
    <MyFace name={person.name} />
    <MyInfo info={person.info} />
  </MyProfileTheme>
)
}

If MyProfile is a Server Component, then ClunkyDependency is not passed to the client in the bundle. Yay!

However, there are some constraints to utilizing server components, namely that it, in an of itself, cannot be interactive. Functions like useState or event handlers cannot be utilized within a server component. However, they can still import client side components which are interactive, but all the interactive logic must be contained within the child client component.

Additionally, any props passed from the parent server component to the child client component must be serializable, ie then can be encoded into JSON.

export function MyProfileTheme({ theme }) {
  const individualTheme = fetchMyTheme();
  return (
    <>
      <IndividualTheme>
        <ThemeHeader
          function={() => doSomething()}
          title={<div>Header Text</div>}
        />
      </IndividualTheme>
    </>
  );
}

For example, if MyProfileTheme is a sever component, then we cannot pass the ‘function’ prop to the ThemeHeader (functions are not serializable). However, we can pass JSX!

Server Components vs Server Side Rendering

Server components are different from SSR. Server side rendering is when the server renders React into HTML quickly, allowing for a first contentful paint of the page, while the Javascript is still being fetched/applied. This means that the initial visuals of the page load rapidly first, while the interactivity/etc loads next.

Conclusions

All in all, server components provide a helpful option for improving performance and reducing bundle size.

  1. https://www.youtube.com/watch?v=TQQPAU21ZUw&ab_channel=MetaOpenSource (Data Fetching with React Server Components)
  2. https://dev.to/nas5w/what-is-the-difference-between-server-side-rendering-ssr-and-react-server-components-5339