ReactでTodoアプリを作っているのだが、stateで管理しているタスクを更新し、更新後のstateをセッションストレージに保存しようとすると、何故か更新前のstateが保存されている。

つまり、更新したはずのstateが反映されていないのだ。

この問題についての解決法を本記事ではまとめていく。

元のコード

stateはuseStateで管理し、以下のフォームからタスクを追加する。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
const [tasks, setTasks] = useState([]);
 
// タスクの追加
const createTask = (e) => {
  e.preventDefault();
  const { taskName } = e.target.elements;
 
  setTasks([{
    name: taskName.value,
    date: dateFormat(new Date()),
  }, ...tasks]);
 
  saveToSessionStorage(tasks);
}

8行目のsetTasksで既存のタスクに新規タスクを追加し、13行目の関数呼び出しでセッションストレージにtasksを保存している。

一見これでうまくいくように見えるが、実はuseStateで管理されるstateは、関数呼び出し後にしか更新されないのだ。

つまり、createTask関数内では更新後のtasksを参照することは出来ないということ。

一時変数に更新後のstateを保存する

この問題を解決するには、更新後のstateをいったん一時変数に保存させておく必要がある。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
const [tasks, setTasks] = useState([]);
 
// タスクの追加
const createTask = (e) => {
  e.preventDefault();
  const { taskName } = e.target.elements;
 
  // 更新後のstateを一時的に保存
  const tmpTasks = [{
    name: taskName.value,
    date: dateFormat(new Date()),
  }, ...tasks];
 
  setTasks(tmpTasks);
 
  saveToSessionStorage(tmpTasks);
 
}

元コードを修正したものがこちら。

9行目、tmpTasksに更新後のstateを一時的に保存し、これをsetTaskssaveToSessionStorageでそれぞれ利用している。

一手間必要になるが、これで更新後のstateを扱うことができるようになる。