useState の set 関数はずっと同じものだった
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ useState の setXXX 関数は state が変わってもずっと同じもの
◆ 毎回変わることで古い更新を防げると思ってた
◆ 毎回変わることで古い更新を防げると思ってた
const [value, setValue] = useState(null)
この setValue 関数ですが これまでは毎回(value が更新されるたび)違う関数になるものだと思っていました
そのおかげで value の更新後にどこかで古い setValue 関数を保持していてもその関数による更新処理は無効になり 古い結果で上書きされることがなくなる利点があると思っていました
例えばボタンを押したときに fetch など非同期処理を挟んで setValue をする場合についてです
1 回目の結果がすぐに届かず ユーザがもう一度ボタンを押して 2 回目の処理が実行されて 2 回目はすぐに結果が届き更新されたとします
その後で時間がかかっていた 1 回目の結果が来て setValue で更新されようとしても それは無効になった古い setValue 関数の実行なので 何も起きず古い結果で更新されることがないというものです
どこでみたのか hook で毎回 [value, setValue] を取得するのは一見ムダだけどこういうメリットがあると思っていました
しかし 実際には setValue は常に同じ関数が返ってきます
ドキュメントを再確認すると 補足的なところで setValue 関数は常に同じになることが保証されています とありました
これまで setValue 関数が毎回変わることを想定して作っていたのに すごい無駄なことをしていました
ref を使って useState に近いことをしたときも わざわざ古い setValue 関数が無効になるような処理を入れていたのですけどね
考えてみると リスナに登録するときに毎回再セットする必要がいらないですし 同じ方が嬉しいときもあります
非同期処理で古い更新をしたくないなら 自分でチェックすれば済みますし
const onClick = async () => {
const sym = ref.current = Symbol()
const new_value = await getSomething()
// イコールじゃないならあとからもう一度クリックされて
// 別の非同期処理が実行されてるはずなのでスキップ
if (ref.current === sym) {
setValue(new_value)
}
}