react-hooks/exhaustive-deps
https://github.com/facebook/react/issues/14920
ESLint の eslint-plugin-react-hooks プラグインのルールの 1 つ
useEffect や useCallback では、第 2 引数に依存関係を配列で渡さないと警告を出す
場合によっては省略することが妥当な場合もある
本当か? radish-miyazaki.icon
react-hooks/exhaustive-deps#66d9c36775d04f00000a996a
e.g. useEffect をマウント時のみ実行したいケース
初期 Props を使って何かしらの初期化を行うなど
この場合、useEffect の第 2 引数は [] になる
しかし、依存関係を省略することはバグの原因となる
そのため、react-hooks/exhaustive-deps は有効にし、どうしても必要な場合は以下のようにしてルールを上書きするのが良い
code:tsx
// eslint-disable-next-line react-hooks/exhaustive-deps
なぜ省略する必要があるのか、必ず理由を記述すること
react-hooks/exhaustive-deps のエラーは 0 にすべき(ルールは上書きしない)という意見もある radish-miyazaki.icon
react-hooks/exhaustive-depsのエラーを0にする
このルールはReactの最も基本的なルールの一つであり、オフにしないとコードを書けないケースはプロダクトコードを書くうえで、基本的に存在しません。
オフにすると以下のような問題が発生する
1. Stale Closure
変更時に含めるべき依存関係を入れ忘れ、値の変更が反映されない
非同期で更新される props 更新の順序が変わると壊れるなどの 競合状態 の発生
ルールをオンにしている限り発生しない問題でバグが発生した場合、特定のレンダリングの順序のみで不具合が発生することになり、原因の特定が非常に難しくなります
2. Reactのバージョンアップ時などに困る問題
useEffect の deps を空にしたからといって、effect が一度しか走らないという保証はありません
Strict Mode では(開発環境で)二回走ります
React の基本的な前提として、何度余分に render しても壊れないコードを書く必要があります
deps を空にして [] を指定して一度しか走らせないようにしているコードは堅牢でなく、render 回数に依存したコードとなっており React の semantics に違反しています
関連して、一度しか effect を走らせないため subscribe 後の cleanup の関数が不要に感じられたとしても、基本的に必ず cleanup は書く必要があります
一度しか走らないことを意図したコードでも、開発中に React の Fast Refresh 時に Component が再レンダリングされるケースが存在します
cleanup のコード を書かないと subscribe などの関数が多重に登録されて開発がしづらくなります
正しい deps を使用しないと、パフォーマンスを大幅にあげる見込みの React Compiler の有効化が難しくなります
どう回避すんの?
https://ja.react.dev/learn/separating-events-from-effects
useEffectEvent を用いる
19 から追加される React Hooks
https://ja.react.dev/learn/separating-events-from-effects#declaring-an-effect-event
code:tsx
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, numberOfItems);
});
useEffect(() => {
onVisit(url);
}, url);