はじめに
Reactでは、useStateの set関数を呼び出すと、すぐにレンダーされずに同じイベントハンドラ内で行われた 複数のstate更新をまとめて処理(バッチ処理)します。
つまり、複数回 setState() を呼び出しても、それぞれが即時反映されるわけではなく、最後に1回レンダーが行われます。
例:3回更新しても1しか増えないケース
次のコードでは、setNumber(number + 1) を3回呼んでいます。
見た目では +3 になるはずですが、実際には 1しか増えません。
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
</>
);
}
なぜ1しか増えないのか?
-
同じレンダー内のstate値は固定される
numberはこのイベントハンドラの中では常に 0 のままです。そのため、3回呼び出しても計算はすべて0 + 1になります。 -
Reactはイベント処理が終わるまで更新を実行しない
Reactは、イベントハンドラ内のコードが全て終わるまで更新を保留し、最後にまとめてレンダーします(バッチ処理)。
解決策: アップデート関数を使う
もし 前のstateの値をもとに更新したい場合 は、setState に関数を渡します。ここで、n => n + 1 は更新用関数 (updater function)と呼びます。
<button onClick={() => {
setNumber(prev => prev + 1);
setNumber(prev => prev + 1);
setNumber(prev => prev + 1);
}}>+3</button>
この場合、prev は常に最新のstateを受け取るため、
1回目は 0 → 1、2回目は 1 → 2、3回目は 2 → 3 となり、期待通り +3 されます。
まとめ
- Reactは複数のstate の更新をまとめて処理する(バッチ処理)
- 前の値を元に更新したい場合は「関数型の state 更新」を使う