【実務・中級編】 状態更新のバッチ処理(Automatic Batching) – React実践ガイド

やあ。現場でReactを触っていると、「あれ、今の状態更新、何回再レンダリング走ったんだ?」とふと不安になることはないか?

React 18から標準化された「Automatic Batching(自動バッチ処理)」。これ、ただの「パフォーマンス向上機能」だと思って甘く見ていると、いざという時に痛い目を見る。今日は、この裏側で何が起きているのか、そして実務でどう付き合うべきか、現場の視点から紐解いていこう。

—

1. Automatic Batchingとは何か?:再レンダリングの「まとめ打ち」

結論から言うと、Automatic Batchingは「Reactが複数のステート更新を待ち構え、最後にまとめて一度だけ再レンダリングを実行する仕組み」だ。

React 17以前は、Reactのイベントハンドラ内ではバッチ処理が効いていたが、`setTimeout`や`Promise`のコールバック、あるいはネイティブなイベントリスナーの中では、状態更新のたびに律儀に再レンダリングが走っていた。これがパフォーマンスのボトルネックになることが多かったんだ。

React 18からは、「どこで更新が起きようが、全部まとめてやるよ」という方針に変わった。これにより、無駄な計算コストが劇的に減ったわけだ。

2. 現場で直面する「バッチ処理の罠」

さて、ここからが本題だ。中級エンジニアがよくハマるポイントがある。「バッチ処理されるなら、直後に最新の値が取れるはずだよね?」という勘違いだ。

以下のコードを見てくれ。

import { useState } from ‘react’;

const Counter = () => {
const [count, setCount] = useState(0);

const handleClick = () => {
// 3回呼び出しているが、Reactはこれをバッチ処理して
// 最後に1回の再レンダリングで済ませる
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);

// ここで console.log(count) しても、結果は 0 のままだ。
// Reactは「今のレンダリングサイクル」内での値を見ているからね。
console.log(‘現在のcount:’, count);
};

return ;
};

このサンプルで、ボタンを一度押すと`count`は「1」になる。3回呼んでいるのに「3」にならないのは、バッチ処理のせいではなく、Reactのステート更新が「非同期的なスナップショット」として処理されるからだ。

これを解決するために `setCount(prev => prev + 1)` という関数型更新を使うのが定石なのは知っていると思うが、「バッチ処理されるからといって、即座に値が更新されるわけではない」という境界線は、常に意識しておいてほしい。

3. どうしても「今すぐ」更新させたい時は?

稀に、バッチ処理を強制的に解除したいケースがある。「状態を更新した直後にDOMの状態を計測したい」といった特殊なインタラクションだ。そんな時は `flushSync` を使う。

import { flushSync } from ‘react-dom’;

const handleForceUpdate = () => {
// flushSyncで囲むと、その処理はバッチ処理されず、
// 即座にReactが再レンダリングを強行する
flushSync(() => {
setCount(c => c + 1);
});

// ここに到達した時点で、すでにDOMは更新されている
console.log(‘DOMは更新済み:’, document.getElementById(‘counter’).innerText);
};

ただし、`flushSync`は劇薬だ。「パフォーマンスを犠牲にしてでも今すぐ同期的に描画する」という明確な理由がない限り、乱用は厳禁。レンダリング回数が増えれば、当然ブラウザのメインスレッドを食いつぶすことになるからな。

4. チーフアーキテクトからのアドバイス

実務で意識すべきは、「バッチ処理の恩恵を信じすぎないこと」だ。

1. レンダリングの回数をデバッグする: `console.log`をコンポーネントのトップレベルに置いておけば、バッチ処理が効いているかどうか一目でわかる。画面がカクついているなら、まずはそこで「レンダリングが何回走っているか」を確認する癖をつけろ。
2. 依存関係の整理: バッチ処理のおかげで、状態更新を並べてもパフォーマンスへの影響は小さくなった。だからこそ、ロジックを無理に詰め込まず、可読性を優先して記述して構わない。
3. React 18以降の恩恵を享受する: 昔の泥臭い「状態更新の最適化(手動でバッチ処理を模倣するようなコード)」は、もう不要だ。モダンな書き方にシフトしていく勇気を持とう。

終わりに

ReactのAutomatic Batchingは、我々エンジニアが「レンダリング回数」という細かなことに頭を悩ませる時間を減らしてくれた。その分、我々は「どんなUIにするか」「どうやってユーザー体験を最大化するか」という、より本質的な課題に集中できるようになったんだ。

もし現場で「なんかレンダリングがおかしいぞ?」と感じたら、まずはReactのレンダリングサイクルを疑い、そして`flushSync`のような手段があることを思い出してくれ。

理論を武器に、今日も最高のアウトプットを積み上げていこうぜ。応援している。

コメント

タイトルとURLをコピーしました