グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



React18 beta の新機能を紹介する【Automatic Batching (自動バッチ処理)編】

最近 React18beta がリリースされました。今回は、React18 で追加される大きな新機能の中から「Automatic Batching(自動バッチ処理)」についてご紹介します。

React18 の新機能

React18 で追加される大きな新機能は下記の通りです。

  • Concurrent Rendering(並行レンダリング)
  • SSR support for Suspense(サスペンスの SSR サポート)
  • Automatic Batching(自動バッチ処理)
  • Selective hydration(選択的ハイドレーション)
  • Built-in Cache(組み込みキャッシュ機構)

今回は自動バッチ処理を React17 と比較してみたいと思います。

インストール

create-react-app ${プロジェクト名}

npm install react@beta react-dom@bet

AutomaticBatching(自動バッチ処理)を検証

今までは関数内でのみバッチ処理を行っていました。
しかし、React18 からはどこから発生したか関係なくすべてのレンダリングがバッチ処理されるようになります。

creat-react-app のコードを流用して実装します。

React18 を導入するためには ReactDOM.render から ReactDOM.createRoot への移行が必須です。

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

↓

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

const root = ReactDOM.createRoot(container);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

検証用のコードです。
onClick で clickHandler 関数を実行します。
clickHandler 関数は setTimeout で非同期でステートを更新します。

const App = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  const [count3, setCount3] = useState(0);

  const clickHandler = () => {
    setTimeout(() => {
      setCount1((count) => count + 1);
      setCount2((count) => count + 1);
      setCount3((count) => count + 1);
    }, 500);
  };

  console.log("rendering!!!");

  return (
    <div className="app">
      <header className="app-header">
        <img src={logo} className="app-logo" alt="logo" />
        <p>{count1}</p>
        <p>{count2}</p>
        <p>{count3}</p>
        <div className="push" onClick={clickHandler}>
          push
        </div>
      </header>
    </div>
  );
};

export default App;

以前の React であれば非同期処理内のステート更新は別々のレンダリングでした。
しかし、React18 ではバッチ処理が行われ、一回でレンダリングしているのがわかります。

React17

React18

バッチ処理をオプトアウトできる API

flushSync でバッチ処理をオプトアウトできます。

import { flushSync } from "react-dom";

const App = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  const [count3, setCount3] = useState(0);

  const clickHandler = () => {
    setTimeout(() => {
      // setCount1だけバッチ処理されない
      ReactDOM.flushSync(() => {
        setCount1((count) => count + 1);
      });
      setCount2((count) => count + 1);
      setCount3((count) => count + 1);
    }, 500);
  };

  console.log("rendering!!!");

  return (
    <div className="app">
      <header className="app-header">
        <img src={logo} className="app-logo" alt="logo" />
        <p>{count1}</p>
        <p>{count2}</p>
        <p>{count3}</p>
        <div className="push" onClick={clickHandler}>
          push
        </div>
      </header>
    </div>
  );
};

export default App;

React18

flushSync のコールバック関数内に切り出せばバッチ処理されません。

さいごに

React 18 における並行レンダリングはオプトインになるため、コンポーネントの振る舞いにおいてデフォルトで大きな破壊的変更があるということはなくなります。 いつものメジャーリリースの時に要する労力と大差ないレベルの最小限の書き換えで、あるいは書き換えゼロで、React 18 にアップグレードすることができます。 「React 18に向けてのプラン」より引用React 18に向けてのプラン

公式に書かれている通り StrictMode で実装していればほぼゼロコストでマイグレーションが可能です。破壊的変更(過去のコードに影響する変更)はオプトインになり、 Automatic Batching などのあまり影響のない変更はデフォルトで有効になるそうです。

React18 のアップデートするだけでもパフォーマンス向上が見込めるので、まだ一般向けリリースまで数か月ありますがアップデートに向けて準備しておくのもいいかもしれません。

この記事を書いた人

アーティス
アーティス
創造性を最大限に発揮するとともに、インターネットに代表されるITを活用し、みんなの生活が便利で、豊かで、楽しいものになるようなサービスやコンテンツを考え、創り出し提供しています。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします