Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eslint-plugin-react-hooks & "Flat Config" (ESLint 9) #28313

Open
Tracked by #18093 ...
JoshuaKGoldberg opened this issue Feb 13, 2024 · 106 comments · May be fixed by #30774
Open
Tracked by #18093 ...

eslint-plugin-react-hooks & "Flat Config" (ESLint 9) #28313

JoshuaKGoldberg opened this issue Feb 13, 2024 · 106 comments · May be fixed by #30774

Comments

@JoshuaKGoldberg
Copy link

JoshuaKGoldberg commented Feb 13, 2024

👋 Coming over from eslint/eslint#18093: ESLint is migrating to a new "flat config" format that will be the default in ESLint v9.

It doesn't look like eslint-plugin-react-hooks has documented support yet. But, based on searching around (e.g. vercel/next.js#49337), ESLint v9 is basically supported if you wire it up manually in your config:

// eslint.config.js
import eslint from "@eslint/js";
import hooksPlugin from "eslint-plugin-react-hooks";

export default [
  eslint.configs.recommended,
  {
    plugins: {
      "react-hooks": hooksPlugin,
    },
    rules: hooksPlugin.configs.recommended.rules,
  },
];

Most community plugins provide a more convenient wrapper. For example, eslint-plugin-jsdoc provides a jsdoc.configs['flat/recommended'] object:

// eslint.config.js
import jsdoc from 'eslint-plugin-jsdoc';

export default [
  jsdoc.configs['flat/recommended'],
];

Would the React team be open to a PR adding in a preset object like that? And either way, updating the docs on https://www.npmjs.com/package/eslint-plugin-react-hooks?

Note: this was also filed as reactjs/react.dev#6430.

I'm posting this issue here as a reference & cross-linking it to the table in eslint/eslint#18093. If there's anything technical blocking the extension from working with flat configs, please let us know - we'd be happy to try to help! 💜

Additional resources:

(sorry for not using the issue templates - I wasn't sure whether this would count as a bug)

@eps1lon
Copy link
Collaborator

eps1lon commented Feb 13, 2024

Thank you for reaching out. What would be involved in creating such a wrapper? Does it make more sense to file a PR and then see how it'll look?

We're only on ESLint 7 though so I guess we need to upgrade that first to test.

@JoshuaKGoldberg
Copy link
Author

What would be involved in creating such a wrapper?

It's not too much work (famous last words, I know). In theory the plugin should be able to get away with exporting an object containing configs, meta, and rules. https://eslint.org/docs/latest/extend/plugin-migration-flat-config#adding-plugin-meta-information shows a very minimal object.

make more sense to file a PR and then see how it'll look?

👍

We're only on ESLint 7 though so I guess we need to upgrade that first to test.

Yeah it feels like it'd probably be cleanest to upgrade to ESLint 8 first, just in case any breaking changes impact the plugin.

@RoystonS
Copy link

RoystonS commented Apr 5, 2024

Note that even wiring up the plugin manually doesn't enable it to work with the now-released ESLint 9: the plugin currently uses APIs like context.getSource which don't exist any more (eslint/eslint#17520), so there'll need to be some upgrade work.

e.g.

`${context.getSource(reactiveHook)} will be lost after each ` +

@JstnMcBrd
Copy link

Eslint officially released v9.0.0 today. However, the eslint-plugin-react-hooks plugin still restricts eslint to v8 in the peerDependencies list, so nobody who uses the plugin can download v9 without breaking dependency resolution.

Hope you'll add support for v9 soon!

@RoystonS
Copy link

RoystonS commented Apr 6, 2024

Should we raise a separate issue for v9 API support?

@yhx-12243
Copy link

yhx-12243 commented Apr 6, 2024

Should we raise a separate issue for v9 API support?

Currently under discussion in jsx-eslint/eslint-plugin-react#3699.

@eps1lon
Copy link
Collaborator

eps1lon commented Apr 6, 2024

ESLint v9 support will be done in #28773

@josiahgallen
Copy link

@eps1lon how far away from merge/release is this update to support eslint v9?

@virtuallyunknown
Copy link

ESLint v9 support will be done in #28773

Hey @eps1lon, greetings!

I just wanted to ask, is #28773 part of the 4.6.0 release that was published on npm 3 days ago or it's planned for a future release?

I am currently in the process of migrating to flat config, and the plugin is giving me an error.

Oops! Something went wrong! :(

ESLint: 9.1.0

TypeError: context.getSource is not a function
Occurred while linting /home/user/projects/eslint-flat-config-migration/src/index.tsx:8
Rule: "react-hooks/exhaustive-deps"
    at visitFunctionWithDependencies (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint-plugin-react-hooks@4.6.0_eslint@9.1.0/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1704:42)
    at visitCallExpression (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint-plugin-react-hooks@4.6.0_eslint@9.1.0/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1759:11)
    at ruleErrorHandler (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/linter.js:1115:48)
    at /home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.enterNode (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
    at runRules (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/linter.js:1154:40)

If needed, here is a my repository where the issue can be reproduced by running npx eslint src/index.tsx

https://github.com/virtuallyunknown/eslint-flat-config-migration

Relevant files:
https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/eslint.config.js
https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/configs/react.js

Cheers!

@JacobZyy
Copy link

ESLint v9 support will be done in #28773

Hey @eps1lon, greetings!

I just wanted to ask, is #28773 part of the 4.6.0 release that was published on npm 3 days ago or it's planned for a future release?

I am currently in the process of migrating to flat config, and the plugin is giving me an error.

Oops! Something went wrong! :(

ESLint: 9.1.0

TypeError: context.getSource is not a function
Occurred while linting /home/user/projects/eslint-flat-config-migration/src/index.tsx:8
Rule: "react-hooks/exhaustive-deps"
    at visitFunctionWithDependencies (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint-plugin-react-hooks@4.6.0_eslint@9.1.0/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1704:42)
    at visitCallExpression (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint-plugin-react-hooks@4.6.0_eslint@9.1.0/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1759:11)
    at ruleErrorHandler (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/linter.js:1115:48)
    at /home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.enterNode (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
    at runRules (/home/user/projects/eslint-flat-config-migration/node_modules/.pnpm/eslint@9.1.0/node_modules/eslint/lib/linter/linter.js:1154:40)

If needed, here is a my repository where the issue can be reproduced by running npx eslint src/index.tsx

https://github.com/virtuallyunknown/eslint-flat-config-migration

Relevant files: https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/eslint.config.js https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/configs/react.js

Cheers!

got the same error and I turn off the rules about react-hooks...

@smaven
Copy link

smaven commented Apr 25, 2024

The issue seems to have been resolved in the canary release.

If you are using eslint-plugin-react, some rules such as react/display-name or other recommended ones don't work: jsx-eslint/eslint-plugin-react#3699.

@eps1lon
Copy link
Collaborator

eps1lon commented Apr 25, 2024

If you are using eslint-plugin-react

eslint-plugin-react is not authored by the React team. Please file an issue for this plugin in https://github.com/jsx-eslint/eslint-plugin-react instead.

ESLint v9 support is available in the Canary release channel (earliest version 5.1.0-canary-cb151849e1-20240424) and will be released as stable with the stable release of React 19.

@virtuallyunknown
Copy link

virtuallyunknown commented Apr 25, 2024

I am not sure if this feedback is of any value, but it looks like the types from eslint and typescript-eslint are signaling about potential issues.

// @ts-check

// @typescript-eslint/utils: 7.7.1
// eslint-plugin-react-hooks: 5.1.0-canary-cb151849e1-20240424

import eslintPluginReactHooks from 'eslint-plugin-react-hooks';

/** @type {import('eslint').Linter.FlatConfig[]} */
export const configuration1 = [
    {
        plugins: {
            'react-hooks': eslintPluginReactHooks
        }
    }
];

/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigFile} */
export const configuration2 = [
    {
        plugins: {
            'react-hooks': eslintPluginReactHooks
        }
    }
];

I don't want to paste the error message because it's a giant wall of text, but feel free to try it on your own.

This appears to be a type error only, and as far as I can tell the plugin is working as expected, so thanks for the updates, much appreciated!

@pkolt
Copy link

pkolt commented Dec 6, 2024

  1. This plugin still doesn't work properly for ESLint 9.
  2. The setup documentation is not updated (ESLint 9 + eslint-plugin-react-hooks 5.1.0).
  3. This is the only configuration that does not cause errors, but the plugin does not check rule exhaustive-deps:
// eslint.config.js
export default [
  {
    plugins: {
      'react-hooks': pluginReactHooks,
       rules: pluginReactHooks.configs.recommended.rules,
     },
  },
];

@michaelfaith
Copy link
Contributor

  1. This plugin still doesn't work properly for ESLint 9.

What about it doesn't work in v9 when not using flat config? You have to disable flat config in v9 to use the config that's in the documentation.

@FerMPY
Copy link

FerMPY commented Dec 8, 2024

It looks like the issue with tseslint persists, but the rule does work as intended, // @ts-expect-error for now until this is resolved I suppose, I just hope it doesn't take forever.

@FerMPY
Copy link

FerMPY commented Dec 9, 2024

@pkolt Switch to flat config. Your config looks nothing like the docs suggest. @FerMPY What issue? I have typescript, eslint, prettier, and jest going and it all works fine. Here's my config...

image

Do you have eslint-plugin-react-hooks working with tselint? because I don't see it in your screenshot.

@dmathisen
Copy link

@pkolt Switch to flat config. Your config looks nothing like the docs suggest. @FerMPY What issue? I have typescript, eslint, prettier, and jest going and it all works fine. Here's my config...
image

Do you have eslint-plugin-react-hooks working with tselint? because I don't see it in your screenshot.

Edit: you're right. I missing that piece. I'm going to delete my answer, as it's not really relevant.

@virtuallyunknown
Copy link

I have a setup with typescript-eslint, eslint-plugin-react-hooks and a bunch of other stuff, and it had been that way since May this year. Just updated everything to latest now, and it's still working, including exhaustive-deps.

Here is a link to the repository. You can clone it, run npm install, and open src/index.tsx in your code editor, it should be full of errors detected by ESLint.

Only posting this here in case someone is struggling and finds this helpful.

@dominictobias
Copy link

dominictobias commented Dec 10, 2024

5.1.0 looks stable. I got this working once on a canary 5.1 but now in a new project with eslint --init and then adding this:

import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginReact from 'eslint-plugin-react'
import pluginReactHooks from 'eslint-plugin-react-hooks' // added

/** @type {import('eslint').Linter.Config[]} */
export default [
  { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  pluginReactHooks.configs.flat.recommended, // added
]
"@eslint/js": "^9.16.0",
"eslint": "^9.16.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
"typescript-eslint": "^8.18.0"

It's not picking up depedency issues in a hook.

Edit: I see there's a pluginReactHooks.configs.recommended and flat version doesn't exist but tried various things and can't get that to work either.

@tejas-1206
Copy link

We just released eslint-plugin-react-hooks@5.0.0. That way you get support for ESLint v9 in a stable release. Check out the release notes for all the changes: https://github.com/facebook/react/releases/tag/eslint-plugin-react-hooks%405.0.0

Works great, thank you!!!
If anyone needs a reference, this is how I got it working… https://github.com/MetroStar/comet-starter/blob/d4e97fb56a73f61656d2cd23eca158772d8d1429/eslint.config.js#L50

Thanks a lot. It works well. Hope there's nothing breaking 🤞🏻

After using it for a week now, I've not faced any issues. Linting works well.

Some of you here are pointing out that deps check isn't working as expected. I don't seem to have any, since its correctly pointing out the missing deps from my useEffect (rule : react-hooks/exhaustive-deps). So, what do y'all mean by deps check not working as expected ? Or am I missing something ?

@pkolt
Copy link

pkolt commented Dec 10, 2024

@tejas-1206

I think users just want this plugin to add flat configuration and update the documentation 🙏
This is the only plugin that didn’t do it, but declared support for ESLint 9 ☹️

I just want to connect it like other plugins, as @dominictobias described above 👍

import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginReact from 'eslint-plugin-react'
import pluginReactHooks from 'eslint-plugin-react-hooks' // added

/** @type {import('eslint').Linter.Config[]} */
export default [
  { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  pluginReactHooks.configs.flat.recommended, // <--- IT DON'T WORK ☹️
]

@tejas-1206
Copy link

@pkolt Same. Even I waited for sometime, for the provision to use flat config. But looks like its gonna take more time and I cannot rollback to older eslint config. So, I went ahead with the below config, based on this reply. My config probably still needs some work w.r.t ordering and extendability for other plugins, but this is working absolutely great for me.

//eslint.config.mjs

import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import unusedImports from 'eslint-plugin-unused-imports';

export default [
  pluginJs.configs.recommended,
  {
    files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'],
    settings: {
      react: {
        version: 'detect'
      }
    },
    languageOptions: {
      parserOptions: {
        ecmaFeatures: {
          jsx: true
        }
      }
    }
  },
  {
    ignores: ['**/dist/*', '**/*.config.{js,mjs,cjs,ts}', '**/node_modules/*']
  },
  { languageOptions: { globals: globals.browser } },
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  eslintPluginPrettierRecommended,
  {
    plugins: {
      'react-hooks': pluginReactHooks
    },
    rules: {
      'react/react-in-jsx-scope': 'off',
      ...pluginReactHooks.configs.recommended.rules
    },
    ignores: ['*.test.tsx']
  },
  // Custom Rules should be added below so that they overwrite any defaults in the above default setup
  {
    plugins: {
      'unused-imports': unusedImports
    },
    rules: {
      // Keep the below 3 rules turned off, so that unused-imports can do its job.
      'react/react-in-jsx-scope': 'off',
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': 'off',

      'unused-imports/no-unused-imports': 'error',
      'unused-imports/no-unused-vars': [
        'warn',
        {
          vars: 'all',
          varsIgnorePattern: '^_',
          args: 'after-used',
          argsIgnorePattern: '^_'
        }
      ],
      // Disable prop-types check as we are using typescript everywhere (Can be enabled again if we need runtime type checking)
      'react/prop-types': [0]
    }
  }
];

@dominictobias
Copy link

dominictobias commented Dec 10, 2024

@pkolt Same. Even I waited for sometime, for the provision to use flat config. But looks like its gonna take more time and I cannot rollback to older eslint config. So, I went ahead with the below config, based on this reply. My config probably still needs some work w.r.t ordering and extendability for other plugins, but this is working absolutely great for me.

//eslint.config.mjs

import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import unusedImports from 'eslint-plugin-unused-imports';

export default [
  pluginJs.configs.recommended,
  {
    files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'],
    settings: {
      react: {
        version: 'detect'
      }
    },
    languageOptions: {
      parserOptions: {
        ecmaFeatures: {
          jsx: true
        }
      }
    }
  },
  {
    ignores: ['**/dist/*', '**/*.config.{js,mjs,cjs,ts}', '**/node_modules/*']
  },
  { languageOptions: { globals: globals.browser } },
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  eslintPluginPrettierRecommended,
  {
    plugins: {
      'react-hooks': pluginReactHooks
    },
    rules: {
      'react/react-in-jsx-scope': 'off',
      ...pluginReactHooks.configs.recommended.rules
    },
    ignores: ['*.test.tsx']
  },
  // Custom Rules should be added below so that they overwrite any defaults in the above default setup
  {
    plugins: {
      'unused-imports': unusedImports
    },
    rules: {
      // Keep the below 3 rules turned off, so that unused-imports can do its job.
      'react/react-in-jsx-scope': 'off',
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': 'off',

      'unused-imports/no-unused-imports': 'error',
      'unused-imports/no-unused-vars': [
        'warn',
        {
          vars: 'all',
          varsIgnorePattern: '^_',
          args: 'after-used',
          argsIgnorePattern: '^_'
        }
      ],
      // Disable prop-types check as we are using typescript everywhere (Can be enabled again if we need runtime type checking)
      'react/prop-types': [0]
    }
  }
];

Thanks! Not sure why it isn't in the docs but I got it to work with your code, for the tl;dr:

import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginReact from 'eslint-plugin-react'
import pluginReactHooks from 'eslint-plugin-react-hooks'

/** @type {import('eslint').Linter.Config[]} */
export default [
  { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  {
    plugins: {
      'react-hooks': pluginReactHooks,
    },
    rules: {
      'react/react-in-jsx-scope': 'off',
      ...pluginReactHooks.configs.recommended.rules,
    },
  },
]

@tejas-1206
Copy link

@dominictobias Great ! I think you probably missed these two comments in this issue, while looking for solutions :

  1. By @eps1lon : eslint-plugin-react-hooks & "Flat Config" (ESLint 9) #28313 (comment)
  2. By @jbouder : eslint-plugin-react-hooks & "Flat Config" (ESLint 9) #28313 (comment)

@pkolt
Copy link

pkolt commented Dec 10, 2024

Maybe this will be useful to someone, I settled on this configuration for the project and it works 👍

// eslint.config.js
import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginReact from 'eslint-plugin-react';
import pluginRefresh from 'eslint-plugin-react-refresh';
import pluginHooks from 'eslint-plugin-react-hooks';

/** @type {import('eslint').Linter.Config[]} */
export default [
  { ignores: ['dist'] },
  {
    files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'],
    settings: {
      react: {
        version: 'detect',
      },
    },
    languageOptions: {
      globals: globals.browser,
    },
  },
  pluginJs.configs.recommended,
  pluginRefresh.configs.recommended,
  pluginReact.configs.flat.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: {
      'react-hooks': pluginHooks,
    },
    rules: {
      'react/react-in-jsx-scope': 'off',
      ...pluginHooks.configs.recommended.rules,
    },
  },
];

@renchris
Copy link

The eslint-config-airbnb plugin does not have the correct type for the Flat Config whether it be using the tselint config helper from typescript-eslint or using the Linter type from eslint

import reactPlugin from "eslint-plugin-react";
import tseslint from 'typescript-eslint';
import { type Linter } from "eslint";

const reactConfigRecommended = reactPlugin.configs.flat!.recommended

const tsEslintConfig = tseslint.config(
    reactConfigRecommended,
);
// error: Argument of type ReactFlagConfig is not assignable to parameter of type InfiniteDepthConfigWithExtends

const linterConfig: Linter.Config[] = [
    reactConfigRecommended,
}];
// error: Type ReactFlagConfig is not assignable to type Config<RulesRecord>

@michaelfaith
Copy link
Contributor

@renchris eslint-plugin-react isn't maintained out of this repo. It's maintained here: https://github.com/jsx-eslint/eslint-plugin-react
This issue is for eslint-plugin-react-hooks

@renchris
Copy link

Ah, okay, thanks. I'll look to raise the discussion issue there.

@alex-r-bigelow
Copy link

FWIW, for anyone already using FlatCompat for other plugins that don't yet have a flat config (e.g. the workaround some people seem to be suggesting for prettier), it also seems to work for react-hooks:

import { FlatCompat } from '@eslint/eslintrc';
import pluginJs from '@eslint/js';
import pluginReact from 'eslint-plugin-react';
import tseslint from 'typescript-eslint';

const compat = new FlatCompat();

/** @type {import('eslint').Linter.Config[]} */
export default [
  {
    files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'],
  },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  ...compat.extends('plugin:prettier/recommended'),
  ...compat.extends('plugin:react-hooks/recommended'),
  {
    rules: {
      'no-debugger': 'warn',
      'no-fallthrough': ['error', { commentPattern: 'break[\\s\\w]*omitted' }],
      'react/react-in-jsx-scope': 'off',
      '@typescript-eslint/no-unused-vars': ['warn'],
    },
  },
];

@mrmckeb
Copy link

mrmckeb commented Dec 24, 2024

Just a quick note that the new eslint-plugin-react-compiler package also doesn't support ESLint 9 / FlatConfig.

@virtuallyunknown
Copy link

Just a quick note that the new eslint-plugin-react-compiler package also doesn't support ESLint 9 / FlatConfig.

If you are certain about this, then it's definitely worth opening a separate issue about it.

@mrmckeb
Copy link

mrmckeb commented Dec 28, 2024

If you are certain about this, then it's definitely worth opening a separate issue about it.

My thought was that it would make sense to address both at once, as they're both published from within this repository.
https://github.com/facebook/react/tree/main/compiler/packages/eslint-plugin-react-compiler

I'm happy to raise a PR for both if the team managing this repo want a hand?

@michaelfaith
Copy link
Contributor

I'm happy to raise a PR for both if the team managing this repo want a hand?

I already have a PR open for hooks, and would gladly do the other, but there are unresolved decisions that the team needs to provide input on the hooks PR, which would apply to the compiler change too. So, no need to create yet another PR, until that's resolved.

@Flaysh
Copy link

Flaysh commented Jan 9, 2025

Hi, is there any update on this issue?

I’m trying to integrate eslint-plugin-react-hooks into my ESLint configuration using tseslint.config([]) but haven’t had any success so far. I’ve tried all the suggested solutions mentioned above, but still can’t get it to work.
I’m currently using ESLint v9. Could you provide guidance or an example to help me set up this plugin properly with tseslint?
Thank you!

@laug
Copy link

laug commented Jan 9, 2025

@Flaysh here is how I do it:

At the top of eslint.config.js:
import reactHooks from 'eslint-plugin-react-hooks'

Under extends: nothing, as this requires the flat config

Under plugins:

plugins: {
      'react': react,
      'react-hooks': reactHooks,
      // ...
}

Under rules:

rules: {
      ...reactHooks.configs.recommended.rules,
      // ...
}

@kachkaev
Copy link
Contributor

kachkaev commented Jan 9, 2025

@Flaysh this worked for me:

eslint.config.js

import eslintPluginReact from "eslint-plugin-react";
import eslintPluginReactHooks from "eslint-plugin-react-hooks";

// ...

  eslintPluginReact.configs.flat?.["recommended"] ?? {},
  eslintPluginReact.configs.flat?.["jsx-runtime"] ?? {},
  {
    rules: {
      "react/jsx-boolean-value": ["error", "always"],
      "react/jsx-curly-brace-presence": "error",
      "react/no-unknown-property": "error",
      "react/prop-types": "off", // handled by TypeScript
      "react/self-closing-comp": "error",
    },
    settings: { react: { version: "detect" } },
  },

  // TODO: Simplify when https://github.com/facebook/react/issues/28313 is resolved
  {
    plugins: {
      "react-hooks": eslintPluginReactHooks,
    },
    rules: { ...eslintPluginReactHooks.configs.recommended.rules },
  },

// ...

declarations/eslint-plugin-react-hooks.d.ts

// TODO: Remove when https://github.com/facebook/react/issues/30119 is resolved

declare module "eslint-plugin-react-hooks" {
  import type { Linter, Rule } from "eslint";

  export const configs: {
    recommended: Linter.Config;
  };

  declare const rules: {
    "rules-of-hooks": Rule.RuleModule;
    "exhaustive-deps": Rule.RuleModule;
  };

  declare const plugin: {
    configs: typeof configs;
    rules: typeof rules;
  };

  export default plugin;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.