Skip to content

Bug: eslint-plugin-react-hooks v.6.1.0 recommended config uses array instead of object #34679

Closed

Description

@anthonyblond

Not sure if this is technically a bug, or just a convention choice.

It's not possible to use the recommended config directly in a flat eslint config array in version 6.1.0

The recommended-latest config (now deprecated) will work, but the new recommended config will not.

The plugin is defined as:

Object.assign(plugin.configs, {
    'recommended-legacy': {
        plugins: ['react-hooks'],
        rules: ruleConfigs,
    },
    'flat/recommended': [
        {
            plugins: {
                'react-hooks': plugin,
            },
            rules: ruleConfigs,
        },
    ],
    'recommended-latest': [
        {
            plugins: {
                'react-hooks': plugin,
            },
            rules: ruleConfigs,
        },
    ],
    recommended: {
        plugins: ['react-hooks'],
        rules: ruleConfigs,
    },
});

The last property should be

    recommended: {
         plugins: {
             'react-hooks': plugin,
         },
        rules: ruleConfigs,
    },

as per https://eslint.org/docs/latest/use/configure/configuration-files#configuration-objects which states

plugins - An object containing a name-value mapping of plugin names to plugin objects. When files is specified, these plugins are only available to the matching files.

React version: 19.1.1

Steps To Reproduce

// eslint.config.js
import jsEslint from '@eslint/js';
import reactHooks from 'eslint-plugin-react-hooks';
import { defineConfig } from 'eslint/config';

export default defineConfig([
  jsEslint.configs.recommended, 
  reactHooks.configs.recommended
]);

The current behaviour

Running eslint

Oops! Something went wrong! :(

ESLint: 9.36.0


A config object has a "plugins" key defined as an array of strings. It looks something like this:

    {
        "plugins": ["react-hooks"]
    }

Flat config requires "plugins" to be an object, like this:

    {
        plugins: {
            react-hooks: pluginObject
        }
    }

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#importing-plugins-and-custom-parsers

If you're using a shareable config that you cannot rewrite in flat config format, then use the compatibility utility:
https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config

The expected behaviour

For it to work the same as if using reactHooks.configs['recommended-latest'] instead.

This isn't a huge deal since there are only two rules, so its easy to just skip the recommended config like the following, but it would nice to be consistent with the way other eslint plugins share their configs.

  {
    plugins: {
      'react-hooks': reactHooksPlugin,
    },
    rules: {
      'react-hooks/exhaustive-deps': 'error',
      'react-hooks/rules-of-hooks': 'error',
    },
  },

Activity

  1. cpojer commented on Oct 2, 2025

    @cpojer
    Contributor

    Yup I also just ran into this, had to go back to 'react-hooks': reactHooks.

  2. josephsavona commented on Oct 2, 2025

    @josephsavona
    Contributor

    Thanks for reporting. I experimented with a bunch of ways to define the plugin, looking at the ESLint docs and examples and trying things out to make sure they worked. Iirc I tried defining it as you suggest and ran into issues when trying to install the plugin, but we’ll definitely take another look!

  3. josephsavona commented on Oct 2, 2025

    @josephsavona
    Contributor

    Note that ESLint docs say that in v9, if you specify “recommended” in your config that it will choose “flat/recommended” if available. We define that too, as you suggest, and left “recommended” in a way that’s backwards compatible w ESLint v8. Is that upgrade to flat config not happening? Are you using the defineConfig() helper?

  4. cpojer commented on Oct 2, 2025

    @cpojer
    Contributor

    @josephsavona Could you copy what eslint-plugin-react does? It exports react.configs.flat.recommended. See nkzw-tech/eslint-config@c388e7f where I had to fix up the setup of eslint-plugin-react-hooks when upgrading to 6.1.0.

    Probably a different discussion, but it would be great to just take over eslint-plugin-react, deprecate/remove some of the silly rules it has, and then merge the hooks plugin into that one. There is really no reason to have more than one ESLint plugin for React.

  5. anthonyblond commented on Oct 2, 2025

    @anthonyblond
    Author

    @josephsavona Happens with defineConfig too.

    I see. I didn't realise the intention was for recommended to be backwards compatible, and to use flat/recommended. That makes sense. I'll just do that.

    As an aside I'm actually using this in typescript and doing

    import reactHooksPlugin from 'eslint-plugin-react-hooks';
    ...
    reactHooksPlugin.configs['flat/recommended'],
    ...

    results in a tsc error saying it doesn't have a .config property. Looking at the package's declaration files its not clear why it thinks it doesn't. Not really relevant to this and easily ignored though :)

  6. brijeshb42 commented on Oct 2, 2025

    @brijeshb42

    It also has typescript issue where I cannot access reactHooksPlugin.configs.recommended with error Property 'configs' does not exist on reactHooksPlugin where reactHooksPlugin is imported as -

    import reactHooksPlugin from 'eslint-plugin-react-hooks';
  7. manferlo81 commented on Oct 2, 2025

    @manferlo81

    It also has typescript issue where I cannot access reactHooksPlugin.configs.recommended with error Property 'configs' does not exist on reactHooksPlugin where reactHooksPlugin is imported as -

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

    Yep!, the types are broken for plugin.configs.

    The problem... plugin.configs is defined as an empty object and then populated using Object.assign so typescript doesn't know it's shape and therefore can't generate types correctly.

    https://github.com/facebook/react/blob/d74f061b6908e4841b2eb09c296ca4658dbdd38e/packages/eslint-plugin-react-hooks/src/index.ts#L28C1-L36C32

    const plugin = {
      meta: {
        name: 'eslint-plugin-react-hooks',
      },
      configs: {},
      rules,
    };
    
    
    Object.assign(plugin.configs, {
    ........
  8. Daniel3711997 commented on Oct 2, 2025

    @Daniel3711997

    "eslint-plugin-react-hooks": "^6.0.0-rc.2"
    Also for the new RC version, the eslint rule 'react compiler' stopped working:
    Key "rules": Key "react-hooks/react-compiler": Could not find "react-compiler" in plugin "react-hooks".

    RC 1 works fine

  9. added a commit that references this issue on Oct 2, 2025
  10. Stanzilla commented on Oct 2, 2025

    @Stanzilla

    Hah okay, I am not alone with this, I though eslint changed something yet again. cc @poteto

  11. added 3 commits that reference this issue on Oct 2, 2025
    ea89302
    7ff8987
    846e132
  12. 9 remaining items

  13. poteto commented on Oct 7, 2025

    @poteto
    Collaborator

    Sorry everyone, this has been more frustrating than expected. eslint's docs clearly seems to be wrong, so I've tried to copy what eslint-plugin-react does in #34762.

    If anyone can help me verify if this experimental release solves the issue, that would help a lot: 0.0.0-experimental-848e0e3a-20251007

  14. kachkaev commented on Oct 7, 2025

    @kachkaev
    Contributor

    👋 @poteto! I tried 0.0.0-experimental-848e0e3a-20251007 after 6.2.0-canary-a4eb2dfa-20251006 (which worked). There seems to be a regression.

    If I add ...eslintPluginReactHooks.configs.recommended, (as before), I get this TSC error:

    Type '{ plugins: string[]; rules: { readonly 'react-hooks/rules-of-hooks': "error"; readonly 'react-hooks/exhaustive-deps': "warn"; }; }' must have a '[Symbol.iterator]()' method that returns an iterator.
    

    and this runtime error:

    TypeError: _eslintPluginReactHooks.default.configs.recommended is not iterable
        at /path/to/my/project/eslint.config.ts:368:44
        at async Function.import (/path/to/my/project/node_modules/jiti/dist/jiti.cjs:1:158301)
    

    If I remove ..., I get this TSC error:

    Type '{ plugins: string[]; rules: { readonly 'react-hooks/rules-of-hooks': "error"; readonly 'react-hooks/exhaustive-deps': "warn"; }; }' is not assignable to type 'Config<RulesRecord>'.
      Types of property 'plugins' are incompatible.
        Type 'string[]' is not assignable to type 'Record<string, Plugin>'.
          Index signature for type 'string' is missing in type 'string[]'.
    

    and this runtime error:

    Oops! Something went wrong! :(
    
    ESLint: 9.36.0
    
    
    A config object has a "plugins" key defined as an array of strings. It looks something like this:
    
        {
            "plugins": ["react-hooks"]
        }
    
    Flat config requires "plugins" to be an object, like this:
    
        {
            plugins: {
                react-hooks: pluginObject
            }
        }
    
    Please see the following page for information on how to convert your config object into the correct format:
    https://eslint.org/docs/latest/use/configure/migration-guide#importing-plugins-and-custom-parsers
    
    If you're using a shareable config that you cannot rewrite in flat config format, then use the compatibility utility:
    https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config
    
  15. pmmmwh commented on Oct 7, 2025

    @pmmmwh

    Sorry everyone, this has been more frustrating than expected. eslint's docs clearly seems to be wrong, so I've tried to copy what eslint-plugin-react does in #34762.

    If anyone can help me verify if this experimental release solves the issue, that would help a lot: 0.0.0-experimental-848e0e3a-20251007

    Both type-checking and invoking ESLint works if the flat.recommended form is used:

    import { defineConfig } from "eslint/config";
    import reactHooks from "eslint-plugin-react-hooks";
    
    export default defineConfig(
    	reactHooks.configs.flat.recommended,
    );
  16. Daniel3711997 commented on Oct 8, 2025

    @Daniel3711997

    Using 6.2.0-canary-3025aa39-20251007 and configs.recommended:

    ⨯ ESLint: Key "rules": Key "react-hooks/react-compiler": Could not find "react-compiler" in plugin "react-hooks".

  17. poteto commented on Oct 8, 2025

    @poteto
    Collaborator

    @Daniel3711997 please use the recommended preset in 7.0.0

  18. Daniel3711997 commented on Oct 9, 2025

    @Daniel3711997

    @poteto now on 7 i get this using the recommended config....⨯ ESLint: Config "UserConfig[0][7] > ExtendedConfig[11]": Key "plugins": This appears to be in eslintrc format (array of strings) rather than flat config format (object).

  19. ArmandRedgate commented on Oct 9, 2025

    @ArmandRedgate

    In v7, I was able to get it working like this:

    import reactHooks from "eslint-plugin-react-hooks";
    
    export default [
      ...
      reactHooks.configs.flat.recommended,
      ...
    ]
  20. Daniel3711997 commented on Oct 10, 2025

    @Daniel3711997

    In v7, I was able to get it working like this:

    import reactHooks from "eslint-plugin-react-hooks";

    export default [
    ...
    reactHooks.configs.flat.recommended,
    ...
    ]

    Using this there is still not react compiler rules:
    ⨯ ESLint: Key "rules": Key "react-hooks/react-compiler": Could not find "react-compiler" in plugin "react-hooks".

    'react-hooks/react-compiler': 'error' - It has been removed?

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      ⌂ Proxy