You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/reference/eslint-plugin-react-hooks/lints/set-state-in-render.md
+18-3Lines changed: 18 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ version: rc
5
5
6
6
<Intro>
7
7
8
-
Validates against setting state during render, which can trigger additional renders and potential infinite render loops.
8
+
Validates against unconditionally setting state during render, which can trigger additional renders and potential infinite render loops.
9
9
10
10
</Intro>
11
11
@@ -19,14 +19,14 @@ You can try it by upgrading the lint plugin [to the most recent RC version](/lea
19
19
20
20
## Rule Details {/*rule-details*/}
21
21
22
-
Calling `setState` during render triggers another render before the current one finishes. This creates an infinite loop that crashes your app.
22
+
Calling `setState` during render unconditionally triggers another render before the current one finishes. This creates an infinite loop that crashes your app.
23
23
24
24
## Common Violations {/*common-violations*/}
25
25
26
26
### Invalid {/*invalid*/}
27
27
28
28
```js {expectedErrors: {'react-compiler': [4]}}
29
-
// ❌ setState directly in render
29
+
// ❌ Unconditional setState directly in render
30
30
functionComponent({value}) {
31
31
const [count, setCount] =useState(0);
32
32
setCount(value); // Infinite loop!
@@ -59,6 +59,19 @@ function Component({user}) {
59
59
constemail= user?.email||'';
60
60
return<div>{name}</div>;
61
61
}
62
+
63
+
// ✅ Conditionally derive state from props and state from previous renders
64
+
functionComponent({ items }) {
65
+
const [isReverse, setIsReverse] =useState(false);
66
+
const [selection, setSelection] =useState(null);
67
+
68
+
const [prevItems, setPrevItems] =useState(items);
69
+
if (items !== prevItems) { // This condition makes it valid
70
+
setPrevItems(items);
71
+
setSelection(null);
72
+
}
73
+
// ...
74
+
}
62
75
```
63
76
64
77
## Troubleshooting {/*troubleshooting*/}
@@ -102,3 +115,5 @@ function Counter({max}) {
102
115
```
103
116
104
117
Now the setter only runs in response to the click, React finishes the render normally, and `count` never crosses `max`.
118
+
119
+
In rare cases, you may need to adjust state based on information from previous renders. For those, follow [this pattern](https://react.dev/reference/react/useState#storing-information-from-previous-renders) of setting state conditionally.
0 commit comments