Yomi Eluwande JavaScript developer. Wannabe designer and Chief Procrastinator at Selar.co and worklogs.co.

Understanding partial hydration in Gatsby 5

4 min read 1289

Gatsby Partial Hydration

At the time of writing, the newest version of Gatsby, v5, ships with partial hydration as a feature. Still in beta, partial hydration enables you to selectively add interactivity to your otherwise completely static app, resulting in improved frontend performance while still keeping the benefits of client-side apps.

In React-based apps and websites, all JavaScript code must be downloaded before the page becomes interactive, affecting the Time to Interactive (TTI) metric in particular. But, thanks to Gatsby’s partial hydration, developers can now hydrate only the necessary JavaScript code for React components, thereby reducing the JavaScript bundle size and increasing page speed.

In React, hydration is the process of using client-side JavaScript to add application state and interactivity to server-rendered HTML. Gatsby implements partial hydration by leveraging React server components to generate the server components’ output, starting from the page level down to isolated components. In this article, we’ll explore partial hydration in a Gatsby and React application.

The motivation behind partial hydration

Most Gatsby sites are content-based, requiring only a few sections to be interactive. However, to ensure that click events, effects, and state changes work correctly, we have to download the JavaScript that handles these events. Unfortunately, this behavior can result in a lot of unused JavaScript code being downloaded, making your website slower and more expensive. Here, partial hydration comes in handy.

According to the Gatsby docs, partial hydration is useful for pages with interactive components where some components need interactivity on a page and some can be statically rendered, for example, a product page with a lot of static content and a few interactive forms and buttons.

Take a look at the following diagram from the Gatsby site. It explains the differences between partial hydration and full hydration.

In this fictional page, the components are mostly static, except for the carousel, which is an interactive component. Typically, when this page is loaded, we request JavaScript code for parts of the site that are static and don’t need it. However, with partial hydration, we request only JavaScript code for the interactive components:

Gatsby Full vs Partial Hydration

What are interactive components?

Interactive components are components that contain useEffect, useState, createContext, or event handlers. Class components are not compatible with server components and should be marked as interactive as well.

How to use partial hydration in Gatsby

Let’s run through an example and learn how to use partial hydration. To get started, install the latest version of Gatsby and experimental versions of React and react-dom:

npm install [email protected] [email protected] [email protected]

Next, go ahead and enable the PARTIAL_HYDRATION flag in the gatsby-config file:

//gatsby.config.js

flags: {
  PARTIAL_HYDRATION: true,
},

By default, Gatsby 5 treats every component as a server component, starting from the top-level pages and generating React Server Components (RSC) files for each page. So, to tell Gatsby to enable partial hydration for a component, you have to add the "use client" directive, an RSC convention, to the top of the component:

// Component.js
"use client";

export function MyInteractiveComponent() {
  const [myState, setState] = useState(null);
  useEffect(() => { setTimeout(() => setState(‘interactive’) }, 3000)

  return <div>{myState}</div>
}

With the "use client" directive, the component will become a special reference object. This object can’t be accessed directly in that file, but it can be passed into React as if it were a plain component. React will then know to send that reference object to the client, which will then be rendered as a client component on the server.

You can see a full example of implementing partial hydration in the Partial Hydration Starter GitHub repository. If you navigate to the src/components/demo.js file, as shown below, you can see a quick example of a client being partially hydrated:

/**
 * To mark a component as client side, you add the "use client" directive.
 * @see {@link https://github.com/reactjs/rfcs/blob/serverconventions-rfc2/text/0000-server-module-conventions.md}
 */
"use client"

import React, { useCallback, useState } from "react"

export function Demo() {
  const [counter, setCounter] = useState(0)
  const onClick = useCallback(() => {
    setCounter(counter => counter + 1)
  }, [])
  return (
    <div style={{ marginTop: "10px", marginBottom: "10px" }}>
      <p style={{ margin: 0 }}>Current counter: {counter}</p>
      <button onClick={onClick}>Add counter</button>
    </div>
  )
}

In the code block above, we have a simple component with a button that will increase the counter using useState. This component is interactive because of its use of useState. This component is imported and utilized in the src/pages/using-partial-hydration.js file, as seen below:

import * as React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import { Demo } from "../components/demo"

function usingPartialHydration() {
  return (
    <Layout>
      <h1>
        Gatsby supports <b>Partial Hydration</b>
      </h1>
      <p>
        You can now mark components as client side. This will reduce Javascript
        shipped to the user.
      </p>
      <p>
        The component below is such a component, if you check the Network Tab
        after a "gatsby build". You will see that we only load the component
        code and non of the layout
      </p>
      {/* Usage of the client component */}
      <Demo />
      <p>
        Checkout <a href="https://gatsby.dev/v5-partial-hydration">the RFC</a>{" "}
        to learn more.
      </p>
      <Link to="/">Go back to the homepage</Link>
    </Layout>
  )
}
export const Head = () => <Seo title="Using TypeScript" />

export default usingPartialHydration

This page component is mostly comprised of a content-filled page, except for the Demo component. When Gatsby tries to build this page, it will generate an RSC file for the page. Instead of fetching page component JavaScript files in the browser, it requests a page-data-rsc.json file. The JSON file is a description of the UI, and any client components are included as a bundle reference to get the actual code of the component.

Right now, partial hydration only works when you build for production, i.e., gatsby build or gatsby serve, and not gatsby develop. When you run gatsby build to build for production, you should see the following lines in the output of the command, which signify that the client components were partially hydrated during the production build:

success Building Partial Hydration renderer - 0.530s
...
success Building partial HTML for pages - 0.040s - 6/6 149.35/s

Known issues with partial hydration

At the time of writing, partial hydration in Gatsby is still in beta. Let’s review some of the currently known issues you might encounter with partial hydration.

Styling libraries

Styling libraries like emotion and styled-components do not currently work when partial hydration is enabled. At the time of writing, React Server Components is not supported.

gatsby-plugin-offline

The gatsby-plugin-offline is used to make a Gatsby site work offline and more resistant to bad network connections. In partial hydration’s beta stage, gatsby-plugin-offline is not supported, and there have been reports of Gatsby sites failing to build.

Conclusion

Setting up partial hydration for your Gatsby site will lead to a good user experience and significantly increase page load speed. The result of shipping less JavaScript code to the client will directly impact your performance scores, most notably the Time to Interactive measurement.

It’s important to keep in mind that partial hydration is still in beta. So, use this in production at your own risk, as there might be some future breaking changes.

To learn more about partial hydration with Gatsby 5, check out the RFC and the conceptual guide. I hope you enjoyed this tutorial, and happy coding!

LogRocket: Full visibility into your production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?

Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.

No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Yomi Eluwande JavaScript developer. Wannabe designer and Chief Procrastinator at Selar.co and worklogs.co.

Leave a Reply