【React】useStateの更新って、めっちゃ遅い
何をしているのか?
ReactでTodoリストを作成中。タスク一覧の表示されるタスクのステータスボタンを押すと、「作業中」→「完了」、「完了」→「作業中」に切り替わる。
今回の課題
タスクのステータスボタンをクリックする度に、ブラウザの表示上ではステータスがちゃんと切り替わっている。
よしよし、ええ感じやん。
念の為、コンソールでステータスを切り替えたタスクのオブジェクトを表示して、ちゃんとステータスが切り替わっているかを確認しよう。
const handleTodoChangeStatus = (id, todoCurrentStatus) => {
setTodoItems((prevTodoItem) => {
return prevTodoItem.map((todoItem) => {
return todoItem.id === id ? { ...todoItem, todoStatus: todoCurrentStatus === NOT_START ? DONE : NOT_START } : todoItem;
})}
)
console.log('ステータスを切り替えたタスク:',todoItems);
}
もう一回、ステータスボタンをクリックしてっと…
…あれ? ステータス(todoStatus)の値が「作業前」→「完了」に切り替わらない…
なんでや、もう一回、クリックしたろ。
なんでや、今度はちゃんと切り替わった。
これ、ちゃんとステータスが更新れているのか?
今回の学び
感覚値として、useStateで管理している値の更新はめっちゃ遅い。
すぐに反映されない。
もっと詳しく調べると、useStateの値の更新と再レンダリングは非同期で処理されるため、stateを更新した直後には値が反映されないのとこと。
今回、コンソールでステータス(todoStatus)の値を確認するため、console.log()を関数に仕込んだ。
この時、useStateの値を更新する処理と、console.log()でタスクの情報をコンソールに出力する処理、2つの処理が同時にスタート。useStateの値の更新は遅い(非同期で処理される)ので、値が更新される前のタスクの情報がコンソールに出力された。だから、ステータスが更新されていないように見えた。
試しに、以下のように、console.log()を2箇所に仕込んでみる。
const handleTodoChangeStatus = (id, todoCurrentStatus) => {
setTodoItems((prevTodoItem) => {
return prevTodoItem.map((todoItem) => {
return todoItem.id === id ? { ...todoItem, todoStatus: todoCurrentStatus === NOT_START ? DONE : NOT_START } : todoItem;
})}
)
console.log('A:',todoItems);
}
console.log('B:',todoItems);
【A】関数が実行される度に、タスクの情報をコンソールに出力。
【B】App.jsがレンダリングされる度に、タスクの情報をコンソールに出力。
同じように、ステータスボタンを押してタスクのステータスを切り替えると、以下のような内容がコンソールに出力される。
handleTodoChangeStatus関数を実行したとき、最初に【A】のコンソールが実行され、todoStatusの値が更新される。その後、stateが更新されたことによってレンダリングが起こり、【B】のコンソールが実行される。その時にはすでにtodoStatsuの値は更新されているので、コンソールには値が更新されたオブジェクトの情報が出力される。
まとめ
useStateは非同期処理で値を更新している。
分かりやすくいうと、useStateの値の更新はめっちゃ遅い。
コンソールに出力する処理の方が早いので、更新されていないように見えるが、ちゃんと更新はされている。
値の更新を確認するために、コンソールを仕込むのは良いが、仕込む場所を間違えないように注意する。useStateの値を更新する関数と同じ場所には仕込まない。
記事を書くスタイルに迷走している感がすごい。
どのように書くのが一番負担が少ないかなぁ…。
この記事が気に入ったらサポートをしてみませんか?