React 18 Features

Neeraj Dana
Neeraj Dana

Installation

you can install React with

npm install react@alpha react-dom@alpha
google drive migration

Automatic Batching

Starting with performance, they have  got huge improvements to automatic batching.

Before React 18, React already batched  multiple state updates into one to reduce unnecessary re-renders. However, it happened only in DOM event handlers, so Promises, timeouts, or other handlers didn’t take advantage of that.

function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    fetchSomething().then(() => {
      // React 18 and later DOES batch these:
      setCount(c => c + 1);
      setFlag(f => !f);
      // React will only re-render once at the end (that's batching!)
    });
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}

To avoid batching

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(f => !f);
  });
  // React has updated the DOM by now
}

New Root Api

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 they 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 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" />);

What are the differences?

There are a few reasons they 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 they don’t need to store the root on the DOM node, though they 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.

Changes in Hydration

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
react jsjavascript