関数型更新とは
useStateの更新時に 現在の状態(state)を引数として受け取り、新しい状態を返す方法です。これだけだとわかりづらいので直接値と関数型アップデートの説明からしていきます。
直接値と関数型アップデートの違い
-
直接値
ステートを直接変更する方法で、古い stateを参照してしまう可能性があります。 -
関数型アップデート
重複してしまいますが、useStateの更新時に、現在の状態(state)を引数として受け取り、新しい状態を返す方法です。現在のステートを引数として受け取り、新しいステートを返す関数を使用してステートを更新し、
前のステートの値を使って新しい値を計算したりすることができます。
常に最新の状態を元に更新するために関数型更新を使います。
簡単に使ってみた
下の処理は毎回「前の状態」を引数に受け取って計算し、順番が守られ、最終的に+3されます。
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
直接関数と比較するとこんな感じです。
const [count, setCount] = useState(0);
// ボタンクリックで3回加算
const handleClick = () => {
setCount(count + 1); // ❌ 非同期なので count は0のまま
setCount(count + 1); // ❌ 再び 0 + 1
setCount(count + 1); // ❌ 結局 setCount(1) が3回
};
const handleClickSafe = () => {
setCount(prev => prev + 1); // ✅ 直前の状態に1加算
setCount(prev => prev + 1); // ✅ さらにその結果に+1
setCount(prev => prev + 1); // ✅ 合計+3される
};
例えばこんな感じで使われる
セイト先生のReact講座の動画を使って進めてみました。クイズアプリを作っている途中の処理です。
const handleClick = (clickedIndex) => {
if (clickedIndex === quizData[quizIndex].answerIndex) {
setAnswerLogs((prev) => [...prev, true]); // クイズの正解 常に最新の状態を使って追加できる
} else {
setAnswerLogs((prev) => [...prev, false]); // クイズが不正解
}
setQuizIndex((prev) => prev + 1); // クイズの問題が終わったら次の問題へ。次の問題に進むための処理 現在のquizIndexに1足して保存する
};
⚫︎補足
prevと書いてあるとこはprev出なくてもOKです。💡
関数型更新を使うべきとき
ChatGPTに聞いてみました。
| 状況 | 関数型更新が必要か? |
|---|---|
| 1回だけ更新する | 不要(どちらでもOK) |
| 複数回連続更新する | ✅ 必須 |
| 状態が非同期で変わる可能性がある | ✅ 推奨 |
| 状態が他の状態と依存している | ✅ 推奨 |
参考資料
ChatGPT