無限ループの回避
onChangeイベントでの無限ループ
onChangeイベントでuseState()
を使いたい時に、下記のようにすると無限ループになる。
import React, {useState} from "react";
export const Hoge= () =>{
const [count,setCount] = useState(0);
const handleButton= () => {
setCount(count+1)
}
return(
<div>
<div>Count: {count}</div>
<button onClick={handleButton()}>Button</button>
</div>
);
}
エラーは下記の通り。
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
翻訳すると、「再レンダリングが多すぎます。 React は、無限ループを防ぐためにレンダリングの数を制限します。」
正しくは、下記のようにアロー関数を使うと無限ループを避けられる。
import React, {useState} from "react";
export const Hoge= () =>{
const [count,setCount] = useState(0);
const handleButton= () => {
setCount(count+1)
}
return(
<div>
<div>Count: {count}</div>
<button onClick={() => handleButton()}>Button</button>
</div>
);
}
render
内をアロー関数で書かないと、render
時にuseState
が呼ばれてしまい、再びrender
され、そこでもuseState
⇒renderm
⇒useState
⇒render
...というループに陥ります。
useEffectでの無限ループ
React ComponentライフサイクルとuseEffect
が実行されるタイミングがバッティングしている時や、useEffect
で発生した副作用を依存配列で参照している時に無限ループになる。
コンポーネントのstate
が更新される度に、Reactはコンポーネントをレンダリングしますが、useEffect
はコンポーネントがレンダリングされる度に、呼び出されるため無限ループになる。
※あまり使わない例
import React, { useState, useEffect } from "react";
export const Hoge= () =>{
const [count, setCount] = useState(0);
useEffect(() => setCount(count+1));
return (
<div>
<div>Count: {count}</div>
</div>
);
}
これに関しては ESLint
の eslint-plugin-react-hooks
を設定しておけば Warning
が表示されるので容易く気付けます。
React Hook useEffect contains a call to 'setCount'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [count] as a second argument to the useEffect Hook.eslintreact-hooks/exhaustive-deps