🛋️
React `useEffect`発火タイミング備忘録
🟡 背景
useEffect
のクリーンアップ関数が思った通りに発火しなかったので、原因を整理するために自分なりにまとめました。
特に、Parent.tsx
でChild.tsx
を表示・非表示(toggle
)する際のuseEffect
発火タイミングに混乱しました。
💡 問題のきっかけ:
-
start
せずにtoggle
→ クリーンアップだけ発火し、本体は発火しない。 -
start
後にtoggle
→ 本体とクリーンアップの両方が発火する。
これにより、「toggle
でアンマウントするならuseEffect
本体も発火するはずでは?」という疑問がありました。
そこで、3パターンの想定でuseEffectの処理の流れをまとめてみました。
Parent
・Child
)
💻 今回使用するコード(Parent.tsx (親コンポーネント)
const Parent = () => {
const [show, setShow] = useState(true);
return (
<>
<button onClick={() => setShow(prev => !prev)}>toggle</button>
{show ? <Child key={show ? "visible" : "hidden"} /> : null}
</>
);
};
Child.tsx (子コンポーネント)
useEffect(() => {
alert("useEffect開始");
if (timerState !== "active") return;
const time = setInterval(() => setCount(prev => prev - ONE_SECONDS), ONE_SECONDS);
return () => {
alert("アンマウント");
clearInterval(time);
};
}, [timerState]);
💡 タイマー機能の発火フロー
1. ページにアクセス(初回マウント)
-
useEffect
本体発火 →alert("useEffect開始")
- クリーンアップは
if (timerState !== "active") return;
で発火せず。
start
を押す(timerState
が変化)
2. -
useEffect
再発火 →alert("useEffect開始")
- クリーンアップが登録される。
stop
を押す(timerState
が変化)
3. - クリーンアップ発火 →
alert("アンマウント")
- 依存値変化で
useEffect
再発火 →alert("useEffect開始")
toggle
での表示・非表示フロー
💡
show = true
)
1. 初回マウント(-
useEffect
発火 →alert("useEffect開始")
- クリーンアップは
timerState
の条件分岐により発火せず。
toggle
で非表示(アンマウント)
2. - クリーンアップ発火 →
alert("アンマウント")
- 本体は条件分岐により発火しない。
toggle
で再表示(再レンダー)
3. -
useEffect
再発火 →alert("useEffect開始")
start
後にtoggle
した場合
💡 1. 初回マウント:
-
useEffect
発火 →alert("useEffect開始")
start
を押す:
2. -
useEffect
再発火 →alert("useEffect開始")
- クリーンアップ関数が登録。
toggle
で非表示:
3. - クリーンアップ発火 →
alert("アンマウント")
-
useEffect
本体は条件分岐により発火しない。
🟠 発火タイミングまとめ表
タイミング | useEffect 本体 (alert("useEffect開始") ) |
クリーンアップ (alert("アンマウント") ) |
---|---|---|
初回マウント | ✅ 発火 | 🚫 未発火 |
toggle (start 前) |
🚫 発火しない | ✅ クリーンアップ発火 |
start 後 |
✅ 再発火 | 🚫 toggle 時まで未発火 |
toggle (start 後) |
🚫 発火しない | ✅ クリーンアップ発火 |
🔵 ポイントまとめ
-
useEffect
は依存配列の値が変わらない限り再発火しない。 -
toggle
はアンマウント扱いでクリーンアップのみ発火する。 - 依存配列が空の場合は**
toggle
で再表示時にuseEffect
が再発火**する。
🟣 最終まとめ
- 依存配列に変更がなければ
useEffect
は再発火しない。 -
toggle
はアンマウント扱いでクリーンアップだけ実行する。 -
start
後は依存値変化で本体とクリーンアップが発火する。 - 依存配列が空の場合は
toggle
で再表示時に再発火する。
まとめた後に見てみると意外と納得のいく処理順序だったので、よく使うからこそしっかり理解できてよかったです。
何か違った認識があったり、参考になるものがあればコメントで教えていただけると助かります🙇♂️
Discussion