ESLintからBiomeへの移行時に特に差分があったexhaustive-depsの挙動について
開発中のプロダクトで、静的解析ツールをESLintからBiomeへ移行しました。基本的にはBiomeが提供するmigrate
コマンドで移行できますが、ツール間で差異があるルールについては修正が必要でした。特に修正量が多かった、Reactの依存配列に関するルールについて詳しく調査しました。
ESLint | Biome |
---|---|
exhaustive-deps | useExhaustiveDependencies |
※ 2024/9/15時点での仕様です
結論として、Biomeのルールの方が依存配列をより厳密にチェックでき、チーム内のコード記述を統一できると感じました。
exhaustive-depsについて
Reactが公式に公開しているESLintプラグインのルールです。
useEffect
などのフックを定義する際の依存配列をLintしてくれます。
// 依存関係の不足
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
}, []); // React Hook useEffect has a missing dependency: 'count'. Either include it or remove the dependency array
ルール違反となるのは主に以下の場合です。
- 依存関係の不足: フック内で使用している変数や関数が依存配列に含まれていない。
- 不要な依存関係: フック内で使用していない変数や関数が依存配列に含まれている。
- 再レンダリングごとに新しい参照が生成される値を依存関係に指定している: 例えば、毎回新しい関数やオブジェクトを生成している場合など。
このルールはBiomeにおいてuseExhaustiveDependencies
というルールで再現されています。
Biomeのルールに移行した際に、エラーとして指摘されるようになった差分をいくつか紹介します。
差分1: 安定な値や関数を依存配列に含めるとエラーになる
useState
のsetState
関数など、再レンダー間で値や参照が変化しないことが保証されている値や関数は、依存配列に含める必要はありません。含めても結果は変わらないのですが、Biomeのルールではこれをエラーとして指摘します。
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((count) => count + 1);
} , [setCount]); // This hook specifies more dependencies than necessary: setCount
このエラー判定が煩わしいという意見もありますが、レビュー時に依存配列を精査する際のコミュニケーションコストを減らすことができます。特に、GitHub CopilotなどのAIアシスト時に意図せず含まれることがあるため、静的解析で記述を統一できるのは利点と考えています。
useEffect
の過剰な依存関係
差分2: ESLintでも、依存配列にフック内で使用していない値を指定するとエラーになりますが、useEffect
ではエラーになりません。開発者が意図的に特定のタイミングで処理を実行したい場合があり、過剰な依存関係が必ずしも問題ではないからです。
const [count, setCount] = useState(0);
useEffect(() => {
console.log("test");
}, [count]); // ESLintではエラーにならない
一方、Biomeの場合は過不足を厳密にチェックし、エラーになります。
const [count, setCount] = useState(0);
useEffect(() => {
console.log("test");
}, [count]); // This hook specifies more dependencies than necessary: count
この差分については、両方に一長一短がありますが、過剰な依存関係を定義する際にignoreコメントを書くことで、意図を明示的に示すことができます。
const [count, setCount] = useState(0);
// biome-ignore lint/correctness/useExhaustiveDependencies: xxの仕様のためcountの更新時にも実行する
useEffect(() => {
console.log("useEffect");
}, [count]);
まとめ
今回は、Biomeへの移行時に特に差分が大きかったルールについて紹介しました。上記で述べた差分以外にも細かな違いがあり、最終的に40ファイルほどを目視で修正しました。
Biomeは、ESLintでは存在したいくつかのルールが欠けているものの、「とにかく速い!」「これまで静的解析でこれほど待っていたことに気づいた」など、チーム内で好評でした。先日のv1.9.0のリリースでついにCSSにも対応したため、Prettierからも移行していく予定です💪!
Discussion