Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ export const EnvironmentConfigSchema = z.object({
*/
validateNoSetStateInRender: z.boolean().default(true),

/**
* When enabled, changes the behavior of validateNoSetStateInRender to recommend
* using useKeyedState instead of the manual pattern for resetting state.
*/
enableUseKeyedState: z.boolean().default(false),

/**
* Validates that setState is not called synchronously within an effect (useEffect and friends).
* Scheduling a setState (with an event listener, subscription, etc) is valid.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,40 @@ function validateNoSetStateInRenderImpl(
}),
);
} else if (unconditionalBlocks.has(block.id)) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.RenderSetState,
reason:
'Calling setState during render may trigger an infinite loop',
description:
'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
suggestions: null,
}).withDetails({
kind: 'error',
loc: callee.loc,
message: 'Found setState() in render',
}),
);
const enableUseKeyedState = fn.env.config.enableUseKeyedState;
if (enableUseKeyedState) {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.RenderSetState,
reason: 'Cannot call setState during render',
description:
'Calling setState during render may trigger an infinite loop.\n' +
'* To reset state when other state/props change, use `const [state, setState] = useKeyedState(initialState, key)` to reset `state` when `key` changes.\n' +
'* To derive data from other state/props, compute the derived data during render without using state',
suggestions: null,
}).withDetails({
kind: 'error',
loc: callee.loc,
message: 'Found setState() in render',
}),
);
} else {
errors.pushDiagnostic(
CompilerDiagnostic.create({
category: ErrorCategory.RenderSetState,
reason: 'Cannot call setState during render',
description:
'Calling setState during render may trigger an infinite loop.\n' +
'* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders\n' +
'* To derive data from other state/props, compute the derived data during render without using state',
suggestions: null,
}).withDetails({
kind: 'error',
loc: callee.loc,
message: 'Found setState() in render',
}),
);
}
}
}
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ export const FIXTURE_ENTRYPOINT = {
```
Found 1 error:

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-setState-in-render-unbound-state.ts:5:2
3 | // infer the type of destructured properties after a hole in the array
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

## Input

```javascript
// @validateNoSetStateInRender @enableUseKeyedState
import {useState} from 'react';

function Component() {
const [total, setTotal] = useState(0);
setTotal(42);
return total;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
isComponent: true,
};

```


## Error

```
Found 1 error:

Error: Cannot call setState during render

Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, use `const [state, setState] = useKeyedState(initialState, key)` to reset `state` when `key` changes.
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-setstate-unconditional-with-keyed-state.ts:6:2
4 | function Component() {
5 | const [total, setTotal] = useState(0);
> 6 | setTotal(42);
| ^^^^^^^^ Found setState() in render
7 | return total;
8 | }
9 |
```


Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @validateNoSetStateInRender @enableUseKeyedState
import {useState} from 'react';

function Component() {
const [total, setTotal] = useState(0);
setTotal(42);
return total;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
isComponent: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ function useCustomState(init) {
```
Found 2 errors:

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-hook-return-in-render.ts:6:2
4 | const aliased = setState;
Expand All @@ -38,9 +40,11 @@ error.invalid-unconditional-set-state-hook-return-in-render.ts:6:2
8 |
9 | return state;

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-hook-return-in-render.ts:7:2
5 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ function Component(props) {
```
Found 2 errors:

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-in-render.ts:6:2
4 | const aliased = setX;
Expand All @@ -34,9 +36,11 @@ error.invalid-unconditional-set-state-in-render.ts:6:2
8 |
9 | return x;

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-in-render.ts:7:2
5 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ function Component({setX}) {
```
Found 2 errors:

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-prop-in-render.ts:5:2
3 | const aliased = setX;
Expand All @@ -33,9 +35,11 @@ error.invalid-unconditional-set-state-prop-in-render.ts:5:2
7 |
8 | return x;

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.invalid-unconditional-set-state-prop-in-render.ts:6:2
4 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ function Component(props) {
```
Found 1 error:

Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render

Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.

error.unconditional-set-state-in-render-after-loop-break.ts:11:2
9 | }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.
error.unconditional-set-state-in-render-after-loop.ts:6:2
4 | for (const _ of props) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.
error.unconditional-set-state-in-render-with-loop-throw.ts:11:2
9 | }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.
error.unconditional-set-state-lambda.ts:8:2
6 | setX(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ function Component(props) {
```
Found 1 error:
Error: Calling setState during render may trigger an infinite loop
Error: Cannot call setState during render
Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState).
Calling setState during render may trigger an infinite loop.
* To reset state when other state/props change, store the previous value in state and update conditionally: https://react.dev/reference/react/useState#storing-information-from-previous-renders
* To derive data from other state/props, compute the derived data during render without using state.
error.unconditional-set-state-nested-function-expressions.ts:16:2
14 | bar();
Expand Down
Loading