Reactの練習で作っているTodoアプリでタスクをstate管理しているのだが、これをセッションストレージに保存する仕組みを作った時のこと。

保存したデータをセッションストレージから読み込み、useStateを使ってstateへセットすると無限ループが発生し以下のエラーメッセージが表示された。

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

この問題についての解決法を今回は紹介する。

エラーとなったコード

以下はエラーとなったコードで、定義したloadFromSessionStorage関数をアプリ起動時に実行し、読み込んだstateをsetTasksへ渡すとエラーが発生する。


function App() {
  const [tasks, setTasks] = useState([]);

  // セッションストレージからタスクを読み込む
  const loadFromSessionStorage = () => {
    try {
      const serializedTasks = sessionStorage.getItem('tasks');
      if(!serializedTasks) {
        return false;
      }
      return JSON.parse(serializedTasks);
    } catch(e) {
      console.log(e);
    }
  }
  
  // 初回起動時にセッションストレージからタスクを読み込む
  const loadTasks = loadFromSessionStorage();
  setTasks(loadTasks);

  // Code...
}

このエラーの原因について調べてみると、Reactではstateが更新されたタイミングでrenderを実行する特性があるため、上記のコードではsetTasksが実行されると再度renderが走り、セッションストレージからの読み込みが繰り返しおこなわれてしまうのだ。

無限ループの回避法

この問題を回避するにはuseEffectを使うと良い。

// 初回起動時にセッションストレージからタスクを読み込む
useEffect(() => {
  const loadTasks = loadFromSessionStorage();
  setTasks(loadTasks);
}, [setTasks]);

上記は先ほどのコードの一部を改変したものだが、こうすることで無限ループを回避することができる。

useEffectの使い方については、正直今の段階で詳しく把握していないが、以下の記事で分かりやすくまとめられていたので勉強の際はよく参考にしている。

https://reffect.co.jp/react/react-useeffect-understanding