ReactにはuseEffectという便利なモノがあります。あるstateの更新を検知して処理をしたり、最初のレンダリング時に処理をしたり、毎回のレンダリング時に処理をすることができます。
フロントの細かいことってしばらくやってないとすぐ忘れるので書きました😎
useEffectでしちゃダメなこと🙅♂️(結論)
useEffect内でstateを更新するのはダメ!!!!
ありがちなパターンは、とあるstateの変更をuseEffectで検知して、それによって別のstateを連動させる場合ですね!
下のNG例では、userの値の変更を検知して、それによってisAdminを連動させています。
function UserProfile() {
const [user, setUser] = useState(null);
const [isAdmin, setIsAdmin] = useState(false);
// 🔴 アンチパターン: 不要なstateと余計なEffect
useEffect(() => {
if (user && user.role === 'admin') {
setIsAdmin(true);
} else {
setIsAdmin(false);
}
}, [user]);
// ...
}
じゃあどうしたらいいのか
既存のstateに基づいて計算される値は、そもそもstateにする必要すらありません!!!
正しくは以下のようになります。
function UserProfile() {
const [user, setUser] = useState(null);
// ✅ 良い例: 派生データを直接計算
const isAdmin = user ? user.role === 'admin' : false;
// ...
}
useEffectが消えたばかりか、isAdminもstateですらなくなりましたね。
正しいuseEffectの使い方は、外部との連携などの副作用を分離させることです。
公式ドキュメントに例を使った記載があります。Reactの公式ドキュメントは丁寧で素晴らしいですね💫💫💫
なぜダメなのか
大前提として、Reactは、stateの更新を検知すると画面を再レンダリングします。
💂< なぜuseEffect内でstateを更新しちゃダメなのかを説明するためには、ReactがuseEffectを処理するタイミングを知る必要がある………
正しいuseEffectの場合
物語はstateが更新されるところから始まります。まず普通のuseEffectは、
- とあるstateが更新される
- 画面の表示内容を計算するためにコンポーネントの関数を再実行
- 更新された内容を画面に表示
- 更新されたstateに依存するuseEffectがある場合、実行
と、レンダリングのあとに実行されます。これがキモです。
ダメなuseEffectの場合
ここで、useEffect内でstateを更新してみましょう。どうなるかというと…………
- とあるstate1が更新される
- 画面の表示内容を計算するためにコンポーネントの関数を再実行
- 更新された内容を画面に表示
- useEffectを実行して、別のstate2を更新😢
- state2が更新されたのを検知して、新しい表示内容を計算するためにコンポーネントの関数をさらに再実行(2回目)
- 更新された内容を画面に表示(2回目)
お気づきでしょうか、画面がムダに2回も計算されていることに…………………………😱😱😱
参考資料
ここにこの記事で説明した全てが書かれています👑👑👑