useEffectの中で状態更新が連鎖する構造をレビューで防ぐ
useEffect
の中で状態を更新する構造は、正しく設計されていれば問題ありません。しかし、依存配列や更新ロジックの設計が曖昧だと、Reactの再レンダリングに伴って useEffect → setState → 再レンダリング → useEffect...
のような状態更新の連鎖構造が発生し、無限ループやパフォーマンス劣化を引き起こします。
本記事では、レビューアーとして useEffect
の中で行われている状態更新が意図されたものか、構造的に安全かを判断する方法を整理します。
よくある無限ループの構造
パターン1:依存配列と状態更新が一致していない
状態連鎖を引き起こす構造
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
}, [count]); // ← countを更新してまた発火
return <div>{count}</div>;
};
コードレビュー
@Reviewer: 状態の更新により依存配列の値が変化し、useEffectが再実行されるループ構造です。明示的な停止条件がないため、無限再レンダリングが発生します。
このような構造は、状態依存の再計算をuseEffect
で処理しようとしているため、Reactの「変更→再評価」サイクルと衝突してしまいます。
構造上の原因を見抜く視点
「状態が再度Effectを呼ぶか?」を構造的に追跡
setState()
によって変更された値がuseEffect
の依存配列に含まれていないかsetState()
によって、自分自身の依存をトリガーしていないか- 更新関数が外部の計算結果に依存していないか
避けるべき構造パターンと代替案
パターン2:propsをstateに写す構造
props → stateコピー構造
const MyComponent = ({ value }: { value: number }) => {
const [internal, setInternal] = useState(value);
useEffect(() => {
setInternal(value);
}, [value]);
return <div>{internal}</div>;
};
コードレビュー
@Reviewer: propsをstateにコピーする構造は原則避けるべきです。直接propsを使う、またはuseMemoでの変換処理を検討してください。
この構造は一見問題なさそうに見えますが、props → state → propsの再反映という構造をとると、思わぬ再実行や副作用のトリガーになりかねません。
設計改善案:変換をuseMemoに任せる
useMemoによる変換構造
const MyComponent = ({ value }: { value: number }) => {
const formatted = useMemo(() => value * 100, [value]);
return <div>{formatted}</div>;
};
コードレビュー
@Reviewer: propsの値を状態に変換せず、memo化された変数として扱うことで、再レンダリングと更新の関係が明示的になっています。
このように、変換・整形と状態保持を明確に分離することで、構造的な再実行の危険を避けられます。
状態更新と依存関係の可視化
パターン3:非同期処理からの状態更新がトリガーに
非同期処理でのループ誘発
useEffect(() => {
fetch("/api/count")
.then(res => res.json())
.then(data => setCount(data.count));
}, [count]); // ← 状態が変わるたびにfetch発火
コードレビュー
@Reviewer: 状態`count`が変わるたびにAPIが再実行される構造です。初回のみ取得したい場合は依存配列を`[]`にするか、明示的な条件を入れてください。
このような構造は、初回取得なのか、依存に応じた再取得なのかの意図が不明確であり、レビューでは意図と実装の乖離がないかを確認する必要があります。
非同期処理の状態更新は依存外で扱うべき
fetchの構造修正
useEffect(() => {
fetch("/api/count")
.then(res => res.json())
.then(data => setCount(data.count));
}, []); // 初回のみ実行
これにより、明確に「初期ロードのみ」という構造が表現され、レビュー時にも意図が読み取りやすくなります。
構造的判断のチェックポイント(レビュー観点)
useEffect
とsetState
は構文的に書けてしまうだけに、レビューアーは構造の循環性と依存トリガーに敏感である必要があります。見逃せば即バグ、見抜けば構造改善への第一歩となる重要なレビュー項目です。