React18のAuto Batchingの確認


背景

Auto Batchingがどのように起こるか確認する。状態変更のたびにレンダリングしていたのが1回になるという言及しているものがあったが、これはもともと1回のはずである。非同期処理で行うと複数回起きてしまうはずである。認識が正しいか確認したい。

まとめ

複数回状態変更したときにReactが複数回レンダリングするかどうか

バージョン 実行タイミング 結果
React17 同期 1回だけ
React17 非同期 複数回
React18 同期 1回だけ
React18 非同期 1回だけ

React18の非同期実行時に明示的にレンダリングを行いたい場合はflushSyncを使う。
補足として、StrictModeを使うとReactElementの作成が複数回起きてしまう点には注意。

確認方法

React18とReact17で確認できるコードを用意した。
内容はこんな感じ(JSXの部分は省略)

  const handleClick = () => {
    setA((a) => a + 1);
    setB((b) => b + 2); // React17でも1度だけ。
  };
  // 別のボタンから呼び出す。setTimeoutを使っている。
  const handleAsyncClick = () => {
    setTimeout(() => {
      setA((a) => a + 1); // React17だとここでレンダリングが発生してしまう
      setB((b) => b + 2);
    }, 0);
  };

  useEffect(() => {
    console.log("effect");
  });

  console.log("render", { a, b });

React18での動作確認用

https://codesandbox.io/s/auto-battching-test-in-18-gf1jts?file=/src/App.js

React17での動作確認用

https://codesandbox.io/s/auto-battching-test-in-17-3ur1lr?file=/src/App.js

React17と同じようにしたい場合は以下のようにする。

  const handleFlushSyncClick = () => {
    setTimeout(() => {
      flushSync(() => {
        setA((a) => a + 1);
      });
      flushSync(() => {
        setB((b) => b + 2);
      });
    }, 0);
  };

–--

このドキュメントは "Chatwork Tech Tips" の一環です。
その他の Tips も含めて にて確認することができます 👨‍🏫