依存配列にオブジェクトを指定した場合のuseEffectの挙動について
Reactの使いはじめの頃、おそらく頻繁に出くわす問題にuseEffectでの無限ループ問題がある。
つまずきがちなのが、以下の例のようにオブジェクトをuseEffectの依存配列に指定した場合である。
const Component = () => {
const [count, setCount] = useState(0);
const hoge = {id:'xxx',name:'test'};
useEffect(() => {
// 無限ループする
setCount(n => n + 1);
}, [hoge]);
return <div>{count}</div>;
};
ここではhogeというオブジェクトをuseEffectの依存配列に指定している。
この場合、次のような実行の流れになってしまい、無限ループが発生する。
- Componentのレンダリングする。このときhogeオブジェクトを生成。
- useEffectの実行
- countの状態を+1する
- countの状態がComponentを再レンダリング。このときhogeオブジェクトを生成。
- hogeオブジェクトの参照先が変更されたのでuseEffectを再実行
- 以降、3から5を繰り返す
このようにhogeオブジェクトがレンダリングのたびに生成されてしまうため、hogeオブジェクトの参照先が変更されてしまい、無限ループが発生する。
問題の対処
この問題を回避する方法はいくつかあるが一番簡単な回避方法は依存配列にオブジェクトではなく、オプジェクトのプロパティを指定する方法である。
const Component = () => {
const [count, setCount] = useState(0);
const hoge = {id:'xxx',name:'test'};
useEffect(() => {
setCount(n => n + 1);
}, [hoge.id]); // 依存配列にhogeオブジェクトのidプロパティを指定。
return <div>{count}</div>;
};
このようにオブジェクトのプロパティを指定しておくとhoge.idのプロパティの値が前のレンダリングの値と変わらない限り、useEffectは実行されない。useEffectの依存配列にオブジェクトを指定して無限ループに陥ってしまった場合の対策方法の参考までに。
補足
もう一つの回避方法としてuseMemoを利用する方法もあるがこの文章では割愛