DEV Community

aldrin
aldrin

Posted on

React 18 things : Automatic Batching

References:
New Feature: Automatic Batching
Discussions: Automatic Batching

What?

Batching in react is the process of grouping multiple state updates into a single re-render. Automatic batching is present in react inside React event handlers, for example, inside handler for a click event. But it was not present for updates inside promises, setTimeout, native event handlers etc. in React 17 or earlier versions.

function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    fetchData().then(() => {
      // React 17 or earlier does NOT batch these updates 
      // These will be two different updates
      setData(data); // 1st update and re-render
      setLoading(false); // 2nd update and re-render
    });
  }, []);

  return (...)
}
Enter fullscreen mode Exit fullscreen mode

With React 18, all updates will be automatically batched, no matter where they originate.

function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    fetchData().then(() => {
      // React 18 and later batch these updates
      setData(data); 
      setLoading(false); 
     // Re-render only once at the end 🥳
    });
  }, []);

  return (...)
}
Enter fullscreen mode Exit fullscreen mode

Why?

Performance reasons: When multiple state updates batch into a single render, we could avoid unnecessary re-renders and thus improve the performance.

How to use?

Upgrade to react 18, this functionality is only available in react 18. It is expected to replace render with createRoot as part of adopting React 18.

How to opt out?

That is a rare case 🤔, you can use ReactDOM.flushSync() to opt out of automatic batching.

import { flushSync } from 'react-dom';

function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    fetchData().then(() => {
      flushSync(() => {
        setData(data); // 1st update and re-render
      });
      flushSync(() => {
        setLoading(false); // 2nd update and re-render
      });

    });
  }, []);

  return ()
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)