A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/reactwg/react-18/discussions/5 below:

Replacing render with createRoot · reactwg/react-18 · Discussion #5 · GitHub

Overview

React 18 ships two root APIs, which we call the Legacy Root API and the New Root API.

Note: the New Root API is available by importing react-dom/client:

import * as ReactDOMClient from 'react-dom/client';

ReactDOMClient.createRoot(/*...*/);

ReactDOMClient.hydrateRoot(/*...*/);

For more information see #125.

What is a root?

In React, a “root” is a pointer to the top-level data structure that React uses to track a tree to render. In the legacy API, the root was opaque to the user because we attached it to the DOM element, and accessed it through the DOM node, never 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);

In the New Root API, the caller creates a root and then calls render on it:

import * as ReactDOMClient from 'react-dom/client';
import App from 'App';

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

// Create a root.
const root = ReactDOMClient.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" />);
What are the differences?

There are a few reasons we changed the API.

First, this fixes some of the ergonomics of the API when running updates. As shown above, in the legacy API, you need to continue to pass the container into render, even though it never changes. This also mean that we don’t need to store the root on the DOM node, though we still do that today.

Second, this change allows us to remove the hydrate method and replace with with an option on the root; and remove the render callback, which does not make sense in a world with partial hydration.

What about hydration?

We’ve moved the hydrate function to a hydrateRoot API.

Before:

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

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

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

After:

import * as ReactDOMClient from 'react-dom/client';

import App from 'App';

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

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

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

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

import * as ReactDOMClient from 'react-dom/client';
import App from 'App';

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

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

// You can later update it.
root.render(<App tab="profile" />);
What about the render callback?

In the legacy root API, you could pass render a callback that is called after the component is 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').
});

In the New Root API, we’ve removed this callback.

With partial hydration and progressive SSR, the timing for this callback would not match what the user expects. To avoid the confusion moving forward, we recommend using requestIdleCallback, setTimeout, or a ref callback on the root.

So instead of this:

import * as ReactDOMClient from 'react-dom/client';

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

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

ReactDOMClient.render(<App />, rootElement, () => console.log("renderered"));

You can do this:

import * as ReactDOMClient from 'react-dom/client';

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 = ReactDOMClient.createRoot(rootElement);
root.render(<App callback={() => console.log("renderered")} />);

See codesandbox.

Why ship both?

We’re shipping the legacy API in React 18 for two reasons:


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4