はじめに
React HooksのuseEffect
フックは、副作用を扱う際に非常に便利ですが、依存配列の設定を誤ると予期せぬ動作やパフォーマンスの問題を引き起こすことがあります。
本記事では、useEffect
の依存配列の誤用について、悪い例と良い例を挙げて解説します。
アンチパターン例:依存配列の誤用
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// この効果は最初のマウント時にのみ実行される
console.log(`カウントが${count}に更新されました`);
}, []); // 依存配列が空
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>インクリメント</button>
</div>
);
}
export default ExampleComponent;
問題点
依存配列が空であるため、countの変更を監視できない
useEffect内でcountを使用しているにもかかわらず、依存配列にcountが含まれていない。
副作用が意図したタイミングで実行されない
countが変化するたびにログを出力したいが、最初のマウント時にしか実行されない。
最適な解決策:依存配列を正しく設定
方法1:依存配列を正しく設定する
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// countが変化するたびに実行される
console.log(`カウントが${count}に更新されました`);
}, [count]); // 依存配列にcountを追加
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>インクリメント</button>
</div>
);
}
export default ExampleComponent;
解説
依存配列にcountを指定
countが変化するたびにuseEffectが再実行される。
意図した副作用の実行
countの変更時にログが正しく出力される。
依存配列を省略した場合
useEffect(() => {
// この効果は毎回のレンダー後に実行される
console.log('コンポーネントがレンダーされました');
});
問題点
毎回のレンダーで実行される
状態やプロップスが変化するたびに効果が実行され、パフォーマンスに悪影響を及ぼす可能性がある。
予期せぬ副作用の発生
依存関係が明示されていないため、バグの原因になりやすい。
なぜ依存配列が重要なのか
useEffectは依存配列を使って、どのタイミングで副作用を実行するかを制御するため、依存配列に指定された値が変化したときにのみ、副作用が再実行されます。
空の依存配列 []
最初のマウント時にのみ実行される。
依存配列を省略
毎回のレンダー後に実行される。
依存配列に値を指定
指定した値が変化したときに実行される。
ベストプラクティス
依存配列に全ての依存関係を含める
useEffect内で使用する全ての状態やプロップス、関数を依存配列に含める。
副作用とレンダーの分離
副作用の中で状態を更新する場合、無限ループにならないよう注意する。
まとめ
useEffectの依存配列は、副作用の実行タイミングを正しく制御するために非常に重要です。
依存配列を正しく設定することで、パフォーマンスの最適化やバグの防止につながります。
さいごに
Reactの基礎的なことですが、開発する際不意にやってしまうので、自分への再勉強としてこれから複数のアンチパターンでまとめたいと思います。
参考
Reactアンチパターン集
【 Reactのアンチパターン 】2, ( React Hooks) 副作用とレンダーの分離:無限ループを防ぐ方法