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

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

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

元のコード

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

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をいったん一時変数に保存させておく必要がある。

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を扱うことができるようになる。