Replacing Render with createRoot is a transparent translation of the class. It is provided by Replacing Render with createRoot

An overview of the

React 18 provides two root apis called the Legacy Root API and the New Root API:

  • Legacy Root API: Refers to the previous version of the Root API, Reactdom.render, which creates a Root that runs in “Legacy” mode and works exactly the same way as React 17. We will add a warning to the API that it will be deprecated and suggest switching to the New Root API.

  • New Root API: The New Root API is reactdom.createroot. It creates a root in React 18 and supports all the new features supported in React 18.

What is a root?

In React, “root” is a pointer to the top-level data structure that React uses to keep track of the tree to render.

In the Legacy Root API, Root is opaque to the user because we attach it to the DOM element and access it through the DOM node without exposing it to the user:

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Initial render.
ReactDOM.render(<App tab="home" />, container);

// During an update, React would access
// the root of the DOM element.
ReactDOM.render(<App tab="profile" />, container);
Copy the code

In the New Root API, createRoot creates a Root and then calls the render method to complete the rendering:

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Create a root.
const root = ReactDOM.createRoot(container);

// Initial render: Render an element to the root.
root.render(<App tab="home" />);

// During an update, there's no need to pass the container again.
root.render(<App tab="profile" />);
Copy the code

What’s the difference?

We changed the API for several reasons.

First, it fixes some ergonomic issues with the API running updates. As shown above, in the Legacy API, you need to pass a container element to Render multiple times, even if it has never changed. This also means that we don’t need to store the root element on the DOM node, although we still do that today.

Second, this change allows us to remove the hydrate method and replace it with an option on root; Delete the render callbacks, which are not meaningful in part hydration.

Translator’s note: “This change allows us to remove the hydrate method and replace it with an option on root.” = = = = = = = = = = = = = = = = = = = = = = = = = .

What is hydration?

We have moved the hydrate function to the hydrateRoot API.

Old version:

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Render with hydration.
ReactDOM.hydrate(<App tab="home" />, container);
Copy the code

The new version:

import * as ReactDOM from 'react-dom';

import App from 'App';

const container = document.getElementById('app');

// Create *and* render a root with hydration.
const root = ReactDOM.hydrateRoot(container, <App tab="home" />);
// Unlike with createRoot, you don't need a separate root.render() call here
Copy the code

Note that, unlike createRoot, hydrateRoot accepts native JSX as the second parameter. This is because the initial client rendering is special and needs to match the server tree.

If you want to update root again after hydration, you can save it in a variable, as with createRoot, and then call root.render() :

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

// Create *and* render a root with hydration.
const root = ReactDOM.hydrateRoot(container, <App tab="home" />);

// You can later update it.
root.render(<App tab="profile" />);
Copy the code

What is a render callback?

In the Legacy Root API, you can pass a callback function to Render that is called after the component has been rendered or updated:

import * as ReactDOM from 'react-dom';
import App from 'App';

const container = document.getElementById('app');

ReactDOM.render(container, <App tab="home" />.function() {
  // Called after inital render or any update.
  console.log('rendered'.)});Copy the code

In the New Root API, we removed this callback.

For partial hydration and progressive SSR, the timing of this callback will not meet the user’s expectations. To avoid confusion, we recommend using requestdlecallBack, setTimeout, or REF callbacks on root.

Not recommended:

import * as ReactDOM from 'react-dom';

function App() {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  );
}

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

ReactDOM.render(<App />, rootElement, () = > console.log("renderered"));
Copy the code

Recommended ways to write:

import * as ReactDOM from 'react-dom';

function App({ callback }) {
  // Callback will be called when the div is first created.
  return (
    <div ref={callback}>
      <h1>Hello World</h1>
    </div>
  );
}

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

const root = ReactDOM.createRoot(rootElement);
root.render(<App callback={()= > console.log("renderered")} />);
Copy the code

See codesandbox

Why support both apis?

There are two reasons to keep the Legacy Root API in React 18:

  • Smooth upgrade: We want to avoid problems with users upgrading to React 18. Instead, we added a warning to the old Root API, recommending that the new API be used.

  • Experimentation: Some applications may experiment to compare the Legacy Root API to the New Root API, including performance improvements out of the box. Both apis are supported in React 18, making it easier for developers to experiment with the two.


Search for “ikoofe” on wechat, follow the public account “KooFE Front-end Team”, and publish front-end technical articles irregularly.