Skip to main content

無限ループの回避

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され、そこでもuseStaterendermuseStaterender...というループに陥ります。

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>
);
}

これに関しては ESLinteslint-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