| 1 | # `eslint-plugin-react-hooks` |
| 2 | |
| 3 | The official ESLint plugin for [React](https://react.dev) which enforces the [Rules of React](https://react.dev/reference/eslint-plugin-react-hooks) and other best practices. |
| 4 | |
| 5 | ## Installation |
| 6 | |
| 7 | Assuming you already have ESLint installed, run: |
| 8 | |
| 9 | ```sh |
| 10 | # npm |
| 11 | npm install eslint-plugin-react-hooks --save-dev |
| 12 | |
| 13 | # yarn |
| 14 | yarn add eslint-plugin-react-hooks --dev |
| 15 | ``` |
| 16 | |
| 17 | ### Flat Config (eslint.config.js|ts) |
| 18 | |
| 19 | Add the `recommended` config for all recommended rules: |
| 20 | |
| 21 | ```js |
| 22 | // eslint.config.js |
| 23 | import reactHooks from 'eslint-plugin-react-hooks'; |
| 24 | import { defineConfig } from 'eslint/config'; |
| 25 | |
| 26 | export default defineConfig([ |
| 27 | reactHooks.configs.flat.recommended, |
| 28 | ]); |
| 29 | ``` |
| 30 | |
| 31 | If you want to try bleeding edge experimental compiler rules, use `recommended-latest`. |
| 32 | |
| 33 | ```js |
| 34 | // eslint.config.js |
| 35 | import reactHooks from 'eslint-plugin-react-hooks'; |
| 36 | import { defineConfig } from 'eslint/config'; |
| 37 | |
| 38 | export default defineConfig([ |
| 39 | reactHooks.configs.flat['recommended-latest'], |
| 40 | ]); |
| 41 | ``` |
| 42 | |
| 43 | ### Legacy Config (.eslintrc) |
| 44 | |
| 45 | If you are still using ESLint below 9.0.0, the `recommended` preset can also be used to enable all recommended rules. |
| 46 | |
| 47 | ```js |
| 48 | { |
| 49 | "extends": ["plugin:react-hooks/recommended"], |
| 50 | // ... |
| 51 | } |
| 52 | |
| 53 | ``` |
| 54 | |
| 55 | ### Custom Configuration |
| 56 | |
| 57 | If you want more fine-grained configuration, you can instead choose to enable specific rules. However, we strongly encourage using the recommended presets — see above — so that you will automatically receive new recommended rules as we add them in future versions of the plugin. |
| 58 | |
| 59 | #### Flat Config (eslint.config.js|ts) |
| 60 | |
| 61 | ```js |
| 62 | import reactHooks from 'eslint-plugin-react-hooks'; |
| 63 | |
| 64 | export default [ |
| 65 | { |
| 66 | files: ['**/*.{js,jsx}'], |
| 67 | plugins: { 'react-hooks': reactHooks }, |
| 68 | // ... |
| 69 | rules: { |
| 70 | // Core hooks rules |
| 71 | 'react-hooks/rules-of-hooks': 'error', |
| 72 | 'react-hooks/exhaustive-deps': 'warn', |
| 73 | |
| 74 | // React Compiler rules |
| 75 | 'react-hooks/config': 'error', |
| 76 | 'react-hooks/error-boundaries': 'error', |
| 77 | 'react-hooks/gating': 'error', |
| 78 | 'react-hooks/globals': 'error', |
| 79 | 'react-hooks/immutability': 'error', |
| 80 | 'react-hooks/preserve-manual-memoization': 'error', |
| 81 | 'react-hooks/purity': 'error', |
| 82 | 'react-hooks/refs': 'error', |
| 83 | 'react-hooks/set-state-in-effect': 'error', |
| 84 | 'react-hooks/set-state-in-render': 'error', |
| 85 | 'react-hooks/static-components': 'error', |
| 86 | 'react-hooks/unsupported-syntax': 'warn', |
| 87 | 'react-hooks/use-memo': 'error', |
| 88 | 'react-hooks/incompatible-library': 'warn', |
| 89 | } |
| 90 | }, |
| 91 | ]; |
| 92 | ``` |
| 93 | |
| 94 | #### Legacy Config (.eslintrc) |
| 95 | ```js |
| 96 | { |
| 97 | "plugins": [ |
| 98 | // ... |
| 99 | "react-hooks" |
| 100 | ], |
| 101 | "rules": { |
| 102 | // ... |
| 103 | // Core hooks rules |
| 104 | "react-hooks/rules-of-hooks": "error", |
| 105 | "react-hooks/exhaustive-deps": "warn", |
| 106 | |
| 107 | // React Compiler rules |
| 108 | "react-hooks/config": "error", |
| 109 | "react-hooks/error-boundaries": "error", |
| 110 | "react-hooks/gating": "error", |
| 111 | "react-hooks/globals": "error", |
| 112 | "react-hooks/immutability": "error", |
| 113 | "react-hooks/preserve-manual-memoization": "error", |
| 114 | "react-hooks/purity": "error", |
| 115 | "react-hooks/refs": "error", |
| 116 | "react-hooks/set-state-in-effect": "error", |
| 117 | "react-hooks/set-state-in-render": "error", |
| 118 | "react-hooks/static-components": "error", |
| 119 | "react-hooks/unsupported-syntax": "warn", |
| 120 | "react-hooks/use-memo": "error", |
| 121 | "react-hooks/incompatible-library": "warn" |
| 122 | } |
| 123 | } |
| 124 | ``` |
| 125 | |
| 126 | ## Advanced Configuration |
| 127 | |
| 128 | `exhaustive-deps` can be configured to validate dependencies of custom Hooks with the `additionalHooks` option. |
| 129 | This option accepts a regex to match the names of custom Hooks that have dependencies. |
| 130 | |
| 131 | ```js |
| 132 | { |
| 133 | rules: { |
| 134 | // ... |
| 135 | "react-hooks/exhaustive-deps": ["warn", { |
| 136 | additionalHooks: "(useMyCustomHook|useMyOtherCustomHook)" |
| 137 | }] |
| 138 | } |
| 139 | } |
| 140 | ``` |
| 141 | |
| 142 | We suggest to use this option **very sparingly, if at all**. Generally saying, we recommend most custom Hooks to not use the dependencies argument, and instead provide a higher-level API that is more focused around a specific use case. |
| 143 | |
| 144 | ## Valid and Invalid Examples |
| 145 | |
| 146 | Please refer to the [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks) documentation to learn more about this rule. |
| 147 | |
| 148 | ## License |
| 149 | |
| 150 | MIT |