ReactJS - hydrateRoot() Method



When building web pages with React, we need to work with HTML content created on the server side. In that situation the hydrateRoot function is very helpful. So we will see what hydrateRoot is, how to use it, and why it is important in some situations.

What exactly is hydrateRoot?

hydrateRoot is a React method that allows us to show React components within a DOM node of a web page. This DOM node already has HTML content that React created on the server. Or simply we can say, it allows us to take control of a portion of a web page that has already been created by React and manage it on the client side.

const root = hydrateRoot(domNode, reactNode, optionalObject)

In simple terms, when we render a React app on the server (instead of the browser), it generates HTML for our components. The hydrateRoot function is then used on the client side to attach event listeners and make the HTML interactive.

This process is known as "hydration." It combines the server-rendered HTML with the client-side JavaScript to create a fully functioning application. Using hydrateRoot helps React optimize the rendering process and enhances the user experience.

Parameters

  • domNode − For putting our React components, we have to first create a DOM element in our web page. This DOM element should correspond to the server-rendered content's root.

  • reactNode − It is the React component that will be rendered inside the DOM node. It is usually a JSX element, such as <App />, that was rendered on the server.

  • optionalObject − We can give an options object with additional parameters. This can contain a callback to handle failures

The hydrateRoot method returns an object with two methods: render and unmount.

The render method is used to update a React component inside the hydrated root.

root.render(reactNode)

And the unmount method is used to destroy the rendered tree inside a React root.

root.unmount()

How to use it?

So we can use hydrateRoot in different ways. First is by hydrating an entire document, second is by handling different client and server content and third by updating a hydrated root component. So we will discuss these one by one.

Examples

Example − Hydrating an entire document

Creating a React app that hydrates the entire document is an effective concept. It helps us to use React components to create a complete web page by including the HTML structure. So we will create an app using this concept −

  • Set up a react app using ‘npx create-react-app’.

  • Now we will create a component for our app. Inside the src folder we will create a new component for the app called App.js.

  • Now, we will use the hydrateRoot function to render our entire React app in the HTML document. In the project folder we have our src/index.js file, so we will replace the existing code with the new code mentioned below.

src/App.js

import React from 'react';

function App() {
   return (
      <html>
         <head>
            <meta charSet="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <link rel="stylesheet" href="/styles.css" />
            <title>My React App</title>
         </head>
         <body>
            <div>
               <h1>Hello, World!</h1>
               <p>This is a simple React app.</p>
            </div>
         </body>
      </html>
   );
}

export default App;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { hydrateRoot } from 'react-dom/client';

const rootElement = document.getElementById('root');
if (rootElement) {
   hydrateRoot(document, <App />);
} else {
   ReactDOM.render(
      <React.StrictMode>
         <App />
      </React.StrictMode>,
      document.getElementById('root')
   );
}

Output

simple reactapp

This code block checks if the rootElement exists. If it exists, it uses hydrateRoot to render the entire document as a React app.

Example − Handling different client and server content

To create a simple app that shows this concept for handling different client and server content. So let’s see the below code −

  • First we need to set up a react app.

  • Now we will create a component that renders different content on the server and the client using two-pass rendering. Inside the src folder we will create a component for the app called App.js.

  • Now, we will start the development server to check the result.

src/App.js

import React, { useState, useEffect } from 'react';

function App() {
   const [isClient, setIsClient] = useState(false);   
   useEffect(() => {
      setIsClient(true);
   }, []);   
   return (
   <div>
      <h1>
         {isClient ? 'Rendered on Client' : 'Rendered on Server'}
      </h1>
   </div>
   );
}

export default App;

Output

rendered on client

In the above code, we have a state variable isClient that we set to true on the client side using the useEffect hook. This lets us present different content as per the rendering occurs on the server or the client.

Example − Updating a hydrated root component

We will create a small React app that displays a counter and refreshes it every second to show a hydrated root component. This concept explains how to use root.render to update a component after it has been hydrated. Let us see the code −

  • First create a new project and navigate to our project directory in the terminal or command prompt.

  • Now we will modify the App component which is present inside the src folder called App.js. Now in this file we will create a simple counter App. In this file the component accepts a counter prop. And this prop is used to initialize the counter value. So the useEffect hook increments the counter every second in the app.

  • Now we will modify the src/index.js file to use hydrateRoot and update the App component every second −

src/App.js

import React, { useState, useEffect } from 'react';

function App({ counter }) {
   const [count, setCount] = useState(counter);   
   useEffect(() => {
   const interval = setInterval(() => {
      setCount(count + 1);
   }, 1000);   
   return () => clearInterval(interval);
   }, [count]);   
   return (
   <div>
      <h1>The Counter: {count}</h1>
      <p>It is updating every second.</p>
   </div>
   );
}

export default App;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { hydrateRoot } from 'react-dom/client';

const rootElement = document.getElementById('root');

if (rootElement) {
   const root = hydrateRoot(rootElement, <App counter={0} />);   
   let i = 0;
   setInterval(() => {
      root.render(<App counter={i} />);
      i++;
   }, 1000);
} else {
   ReactDOM.render(
      <React.StrictMode>
         <App counter={0} />
      </React.StrictMode>,
      rootElement
   );
}

Output

the counter 6 updating

This code initializes the root using hydrateRoot and then calls root.render continuously to update the App component with an increased counter value per second.

Limitations

  • When we use hydrateRoot, it expects the content we have previously displayed on our web page to be similar to what the server has placed there. It is an issue if they don't match.

  • If we try to change anything on the web page before React has finished setting things up (this is hydration), React will delete everything and start again.

  • We use root.unmount to remove everything from the web page that React was handling.

Summary

React's hydrateRoot method is a powerful mechanism which allows us to update and control React content on the client side while ensuring effective performance. But hydrateRoot is often used when we wish to enhance server-rendered HTML content with dynamic React components.

reactjs_reference_api.htm
Advertisements