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