React学習5日目:バッチ処理と関数型アップデート
ステートセッターを複数回呼び出すと、レンダリングも複数回発生すると思っていました。
私の勘違いでした。
Reactはもっと賢いです。「Automatic Batching(自動バッチ処理)」と呼ばれるプロセスを使用しています。
更新のたびにレンダリングするのではなく、Reactはそれらをグループ化します。すべての更新をまとめて、一度のレンダリングで実行します。これによりパフォーマンスが向上します。
今日学んだことは以下の通りです。
バッチ処理のプロセス
複数のステート関数を呼び出すと、Reactは以下のフローに従います。
- 複数のステート更新が発生する。
- Reactがそれらをまとめてバッチ処理する。
- Reactが一度だけレンダリングを実行する。
- ReactがUIに変更をコミットする。
標準的なアップデートの問題点
次のようなコードを試してみました。
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
カウントが0から3になると予想していましたが、実際には0から1になりました。
これは、setCount(count + 1) が「カウントを増やす」という意味ではなく、「カウントをこの特定の値に設定する」という意味だからです。
もし count が0であれば、すべての行がReactに対して「カウントを1に設定せよ」と指示していることになります。Reactはこれらをバッチ処理し、最終的な指示が「カウントを1に設定する」であると判断します。
解決策:関数型アップデート
これを解決するには、関数型アップデートを使用する必要があります。これを使うと、アップデートキューにある最新のステートを利用できます。
正しい方法:
setCount((prev) => prev + 1);
このパターンを使用すると、Reactは各アップデートに最新の値を与えます。
- 最初のアップデート: 0 + 1 = 1
- 2番目のアップデート: 1 + 1 = 2
- 3番目のアップデート: 2 + 1 = 3
これで、カウンターは実際に3に到達します。
よくある間違い
以前、このように書いてしまいました。
setCount((prev) => { prev + 1 });
カウンターが undefined になってしまいました。
アロー関数で波括弧 {} を使用する場合は、return キーワードを使用する必要があります。
代わりにこちらを使用してください:
setCount((prev) => prev + 1);
まとめ:
- Reactは速度向上のために複数のステート更新をバッチ処理する。
setStateの呼び出しが常に即座にレンダリングをトリガーするわけではない。- 標準的なアップデートは、現在のレンダリングサイクルの値を使用する。
- 関数型アップデートは、アップデートキュー内の最新のステートを使用する。
- Reactはこれらの変更を管理するために、内部の Update Queue(アップデートキュー)を使用する。
