Skip to content

Commit bb4d30a

Browse files
committed
Add new eslint rule reference docs
Adds new docs for our new eslint rules.
1 parent 454dfce commit bb4d30a

20 files changed

+1879
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: eslint-plugin-react-hooks
3+
---
4+
5+
<Intro>
6+
7+
`eslint-plugin-react-hooks` provides ESLint rules to enforce the [Rules of React](/reference/rules).
8+
9+
</Intro>
10+
11+
This plugin helps you catch violations of React's rules at build time, ensuring your components and hooks follow React's rules for correctness and performance. The lints cover both fundamental React patterns (exhaustive-deps and rules-of-hooks) and issues flagged by React Compiler. React Compiler diagnostics are automatically surfaced by this ESLint plugin, and can be used even if your app hasn't adopted the compiler yet.
12+
13+
<Note>
14+
When the compiler reports a diagnostic, it means that the compiler was able to statically detect a pattern that is not supported or breaks the Rules of React. When it detects this, it **automatically** skips over those components and hooks, while keeping the rest of your app compiled. This ensures optimal coverage of safe optimizations that won't break your app.
15+
16+
What this means for linting, is that you don’t need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components.
17+
</Note>
18+
19+
## Available Lints {/*available-lints*/}
20+
21+
* [`component-hook-factories`](/reference/eslint-plugin-react-hooks/lints/component-hook-factories) - Validates against higher order functions defining nested components or hooks
22+
* [`config`](/reference/eslint-plugin-react-hooks/lints/config) - Validates the compiler configuration options
23+
* [`error-boundaries`](/reference/eslint-plugin-react-hooks/lints/error-boundaries) - Validates usage of Error Boundaries instead of try/catch for child errors
24+
* [`exhaustive-deps`](/reference/eslint-plugin-react-hooks/lints/exhaustive-deps) - Validates that dependency arrays for React hooks contain all necessary dependencies
25+
* [`gating`](/reference/eslint-plugin-react-hooks/lints/gating) - Validates configuration of gating mode
26+
* [`globals`](/reference/eslint-plugin-react-hooks/lints/globals) - Validates against assignment/mutation of globals during render
27+
* [`immutability`](/reference/eslint-plugin-react-hooks/lints/immutability) - Validates against mutating props, state, and other immutable values
28+
* [`incompatible-library`](/reference/eslint-plugin-react-hooks/lints/incompatible-library) - Validates against usage of libraries which are incompatible with memoization
29+
* [`preserve-manual-memoization`](/reference/eslint-plugin-react-hooks/lints/preserve-manual-memoization) - Validates that existing manual memoization is preserved by the compiler
30+
* [`purity`](/reference/eslint-plugin-react-hooks/lints/purity) - Validates that components/hooks are pure by checking known-impure functions
31+
* [`refs`](/reference/eslint-plugin-react-hooks/lints/refs) - Validates correct usage of refs, not reading/writing during render
32+
* [`rules-of-hooks`](/reference/eslint-plugin-react-hooks/lints/rules-of-hooks) - Validates that components and hooks follow the Rules of Hooks
33+
* [`set-state-in-effect`](/reference/eslint-plugin-react-hooks/lints/set-state-in-effect) - Validates against calling setState synchronously in an effect
34+
* [`set-state-in-render`](/reference/eslint-plugin-react-hooks/lints/set-state-in-render) - Validates against setting state during render
35+
* [`static-components`](/reference/eslint-plugin-react-hooks/lints/static-components) - Validates that components are static, not recreated every render
36+
* [`unsupported-syntax`](/reference/eslint-plugin-react-hooks/lints/unsupported-syntax) - Validates against syntax that React Compiler does not support
37+
* [`use-memo`](/reference/eslint-plugin-react-hooks/lints/use-memo) - Validates usage of the `useMemo` hook without a return value
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
title: component-hook-factories
3+
---
4+
5+
<Intro>
6+
7+
Validates against higher order functions defining nested components or hooks. Components and hooks should be defined at the module level.
8+
9+
</Intro>
10+
11+
## Rule Details {/*rule-details*/}
12+
13+
Defining components or hooks inside other functions creates new instances on every call. React treats each as a completely different component, destroying and recreating the entire component tree, losing all state, and causing performance problems.
14+
15+
### Invalid {/*invalid*/}
16+
17+
Examples of incorrect code for this rule:
18+
19+
```js {expectedErrors: {'react-compiler': [14]}}
20+
// ❌ Factory function creating components
21+
function createComponent(defaultValue) {
22+
return function Component() {
23+
// ...
24+
};
25+
}
26+
27+
// ❌ Component defined inside component
28+
function Parent() {
29+
function Child() {
30+
// ...
31+
}
32+
33+
return <Child />;
34+
}
35+
36+
// ❌ Hook factory function
37+
function createCustomHook(endpoint) {
38+
return function useData() {
39+
// ...
40+
};
41+
}
42+
```
43+
44+
### Valid {/*valid*/}
45+
46+
Examples of correct code for this rule:
47+
48+
```js
49+
// ✅ Component defined at module level
50+
function Component({ defaultValue }) {
51+
// ...
52+
}
53+
54+
// ✅ Custom hook at module level
55+
function useData(endpoint) {
56+
// ...
57+
}
58+
```
59+
60+
## Troubleshooting {/*troubleshooting*/}
61+
62+
### I need dynamic component behavior {/*dynamic-behavior*/}
63+
64+
You might think you need a factory to create customized components:
65+
66+
```js
67+
// ❌ Wrong: Factory pattern
68+
function makeButton(color) {
69+
return function Button({children}) {
70+
return (
71+
<button style={{backgroundColor: color}}>
72+
{children}
73+
</button>
74+
);
75+
};
76+
}
77+
78+
const RedButton = makeButton('red');
79+
const BlueButton = makeButton('blue');
80+
```
81+
82+
Pass [JSX as children](learn/passing-props-to-a-component#passing-jsx-as-children) instead:
83+
84+
```js
85+
// ✅ Better: Pass JSX as children
86+
function Button({color, children}) {
87+
return (
88+
<button style={{backgroundColor: color}}>
89+
{children}
90+
</button>
91+
);
92+
}
93+
94+
function App() {
95+
return (
96+
<>
97+
<Button color="red">Red</Button>
98+
<Button color="blue">Blue</Button>
99+
</>
100+
);
101+
}
102+
```
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
title: config
3+
---
4+
5+
<Intro>
6+
7+
Validates the compiler [configuration options](/reference/react-compiler/configuration).
8+
9+
</Intro>
10+
11+
## Rule Details {/*rule-details*/}
12+
13+
React Compiler accepts various [configuration options](/reference/react-compiler/configuration) to control its behavior. This rule validates that your configuration uses correct option names and value types, preventing silent failures from typos or incorrect settings.
14+
15+
### Invalid {/*invalid*/}
16+
17+
Examples of incorrect code for this rule:
18+
19+
```js
20+
// ❌ Unknown option name
21+
module.exports = {
22+
plugins: [
23+
['babel-plugin-react-compiler', {
24+
compileMode: 'all' // Typo: should be compilationMode
25+
}]
26+
]
27+
};
28+
29+
// ❌ Invalid option value
30+
module.exports = {
31+
plugins: [
32+
['babel-plugin-react-compiler', {
33+
compilationMode: 'everything' // Invalid: use 'all' or 'infer'
34+
}]
35+
]
36+
};
37+
```
38+
39+
### Valid {/*valid*/}
40+
41+
Examples of correct code for this rule:
42+
43+
```js
44+
// ✅ Valid compiler configuration
45+
module.exports = {
46+
plugins: [
47+
['babel-plugin-react-compiler', {
48+
compilationMode: 'infer',
49+
panicThreshold: 'critical_errors'
50+
}]
51+
]
52+
};
53+
```
54+
55+
## Troubleshooting {/*troubleshooting*/}
56+
57+
### Configuration not working as expected {/*config-not-working*/}
58+
59+
Your compiler configuration might have typos or incorrect values:
60+
61+
```js
62+
// ❌ Wrong: Common configuration mistakes
63+
module.exports = {
64+
plugins: [
65+
['babel-plugin-react-compiler', {
66+
// Typo in option name
67+
compilationMod: 'all',
68+
// Wrong value type
69+
panicThreshold: true,
70+
// Unknown option
71+
optimizationLevel: 'max'
72+
}]
73+
]
74+
};
75+
```
76+
77+
Check the [configuration documentation](/reference/react-compiler/configuration) for valid options:
78+
79+
```js
80+
// ✅ Better: Valid configuration
81+
module.exports = {
82+
plugins: [
83+
['babel-plugin-react-compiler', {
84+
compilationMode: 'all', // or 'infer'
85+
panicThreshold: 'none', // or 'critical_errors', 'all_errors'
86+
// Only use documented options
87+
}]
88+
]
89+
};
90+
```
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
title: error-boundaries
3+
---
4+
5+
<Intro>
6+
7+
Validates usage of Error Boundaries instead of try/catch for errors in child components.
8+
9+
</Intro>
10+
11+
## Rule Details {/*rule-details*/}
12+
13+
Try/catch blocks can't catch errors that happen during React's rendering process. Errors thrown in rendering methods or hooks bubble up through the component tree. Only [Error Boundaries](/reference/react/Component#catching-rendering-errors-with-an-error-boundary) can catch these errors.
14+
15+
### Invalid {/*invalid*/}
16+
17+
Examples of incorrect code for this rule:
18+
19+
```js {expectedErrors: {'react-compiler': [4]}}
20+
// ❌ Try/catch won't catch render errors
21+
function Parent() {
22+
try {
23+
return <ChildComponent />; // If this throws, catch won't help
24+
} catch (error) {
25+
return <div>Error occurred</div>;
26+
}
27+
}
28+
```
29+
30+
### Valid {/*valid*/}
31+
32+
Examples of correct code for this rule:
33+
34+
```js
35+
// ✅ Using error boundary
36+
function Parent() {
37+
return (
38+
<ErrorBoundary>
39+
<ChildComponent />
40+
</ErrorBoundary>
41+
);
42+
}
43+
```
44+
45+
## Troubleshooting {/*troubleshooting*/}
46+
47+
### Why is the linter telling me not to wrap `use` in `try`/`catch`? {/*why-is-the-linter-telling-me-not-to-wrap-use-in-trycatch*/}
48+
49+
The `use` hook doesn't throw errors in the traditional sense, it suspends component execution. When `use` encounters a pending promise, it suspends the component and lets React show a fallback. Only Suspense and Error Boundaries can handle these cases. The linter warns against `try`/`catch` around `use` to prevent confusion as the `catch` block would never run.
50+
51+
```js {expectedErrors: {'react-compiler': [5]}}
52+
// ❌ Try/catch around `use` hook
53+
function Component({promise}) {
54+
try {
55+
const data = use(promise); // Won't catch - `use` suspends, not throws
56+
return <div>{data}</div>;
57+
} catch (error) {
58+
return <div>Failed to load</div>; // Unreachable
59+
}
60+
}
61+
62+
// ✅ Error boundary catches `use` errors
63+
function App() {
64+
return (
65+
<ErrorBoundary fallback={<div>Failed to load</div>}>
66+
<Suspense fallback={<div>Loading...</div>}>
67+
<DataComponent promise={fetchData()} />
68+
</Suspense>
69+
</ErrorBoundary>
70+
);
71+
}
72+
```

0 commit comments

Comments
 (0)