2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

この記事では、ESLint の Flat Config に React Hooks 向けルールのプラグインである eslint-plugin-react-hooks を追加する手順について記載します。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • VSCode
  • TypeScript 5.2.2
  • React 18.3.1
  • Vite 5.3.1
  • Node.js 20.15.0
  • npm 10.8.1
  • ESLint 8.57.0
  • Prettier 3.3.2
  • @eslint/js 9.6.0
  • eslint-config-prettier 9.1.0
  • eslint-plugin-jsx-a11y 6.9.0
  • eslint-plugin-react 7.34.3
  • eslint-plugin-react-hooks 4.6.2
  • globals 15.8.0
  • typescript-eslint 7.15.0

事前準備

プロジェクトに ESLint のインストール・設定をしておきます。
React / TypeScript 環境における詳細手順はこちら。

Prettier を追加する手順はこちら。

eslint-plugin-react-hooks のインストール

eslint-plugin-react-hooks をインストールします。

npm install eslint-plugin-react-hooks --save-dev

一括設定

今までの記事で扱った以下のプラグインと異なり、2024年7月時点で、eslint-plugin-react-hooks には Flat Config 向けの共有設定(Shareable Configs)が提供されていないようです。

そのため、上記のプラグインとは、設定方法が異なります。

  • eslint-plugin-react-hooks をインポート
  • pugins"react-hooks": pluginReactHooks を追加
  • rules...pluginReactHooks.configs.recommended.rules を追加
eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
import pluginReactHooks from "eslint-plugin-react-hooks"; // Add
import jsxA11y from "eslint-plugin-jsx-a11y";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
  {
    files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
    settings: {
      react: {
        version: "detect",
      },
    },
    plugins: {
      "react-hooks": pluginReactHooks, // Add
    },
    rules: {
      ...pluginReactHooks.configs.recommended.rules, // Add
    },
  },
  { languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
  { languageOptions: { globals: globals.browser } },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReactConfig,
  pluginReactJSXRuntime,
  jsxA11y.flatConfigs.recommended,
  eslintConfigPrettier,
];

動作確認

useEffectdependencies がない状態で、ESLint を実行してみます。

App.tsx
import { useEffect, useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    alert("Count: " + count);
  }, []); // no dependencies

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank" rel="noreferrer">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank" rel="noreferrer">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  );
}

export default App;

以下のワーニングが表示されます。

11:6  warning  React Hook useEffect has a missing dependency:'count'. 
Either include it or remove the dependency array
react-hooks/exhaustive-deps

 1 problem (0 errors, 1 warning)

count を追加するとワーニングが消えます。

App.tsx
import { useEffect, useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    alert("Count: " + count);
  }, [count]); // Add

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank" rel="noreferrer">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank" rel="noreferrer">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  );
}

export default App;

個別設定

eslint-plugin-react-hooks の各ルールを個別に設定することもできます。
rules...pluginReactHooks.configs.recommended.rules の代わりに個別のルールを記載することで設定できます。

eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
import pluginReactHooks from "eslint-plugin-react-hooks";
import jsxA11y from "eslint-plugin-jsx-a11y";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
  {
    files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
    settings: {
      react: {
        version: "detect",
      },
    },
    plugins: {
      "react-hooks": pluginReactHooks,
    },
    rules: {
      "react-hooks/exhaustive-deps": "error", // Add
    },
  },
  { languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
  { languageOptions: { globals: globals.browser } },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReactConfig,
  pluginReactJSXRuntime,
  jsxA11y.flatConfigs.recommended,
  eslintConfigPrettier,
];

参考

関連記事

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?