[compiler] Improve more error messages (#33758)
This PR uses the new diagnostic type for most of the error messages produced in our explicit validation passes (`Validation/` directory). One of the validations produced multiple errors as a hack to showing multiple related locations, which we can now consolidate into a single diagnostic. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33758). * #33981 * #33777 * #33767 * #33765 * #33760 * #33759 * __->__ #33758
Joseph Savona committed
Jul 24, 2025 at 15:39 UTC
72848027a5525d7beebeccb0a485f4f211a1a101
41 files changed
+324
-262
compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts
+13
-2
@@ -59,7 +59,7 @@ export type CompilerDiagnosticDetail =
59
*/
60
{
61
kind: 'error';
62
- loc: SourceLocation;
62
+ loc: SourceLocation | null;
63
message: string;
64
};
65
@@ -100,6 +100,12 @@ export class CompilerDiagnostic {
100
this.options = options;
101
}
102
103
+ static create(
104
+ options: Omit<CompilerDiagnosticOptions, 'details'>,
105
+ ): CompilerDiagnostic {
106
+ return new CompilerDiagnostic({...options, details: []});
107
+ }
108
+
109
get category(): CompilerDiagnosticOptions['category'] {
110
return this.options.category;
111
}
@@ -113,6 +119,11 @@ export class CompilerDiagnostic {
119
return this.options.suggestions;
120
}
121
122
+ withDetail(detail: CompilerDiagnosticDetail): CompilerDiagnostic {
123
+ this.options.details.push(detail);
124
+ return this;
125
+ }
126
+
127
primaryLocation(): SourceLocation | null {
128
return this.options.details.filter(d => d.kind === 'error')[0]?.loc ?? null;
129
}
@@ -127,7 +138,7 @@ export class CompilerDiagnostic {
138
switch (detail.kind) {
139
case 'error': {
140
const loc = detail.loc;
130
- if (typeof loc === 'symbol') {
141
+ if (loc == null || typeof loc === 'symbol') {
142
continue;
143
}
144
let codeFrame: string;
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+37
-19
@@ -9,6 +9,7 @@ import {NodePath, Scope} from '@babel/traverse';
9
import * as t from '@babel/types';
10
import invariant from 'invariant';
11
import {
12
+ CompilerDiagnostic,
13
CompilerError,
14
CompilerSuggestionOperation,
15
ErrorSeverity,
@@ -104,12 +105,18 @@ export function lower(
105
if (param.isIdentifier()) {
106
const binding = builder.resolveIdentifier(param);
107
if (binding.kind !== 'Identifier') {
107
- builder.errors.push({
108
- reason: `(BuildHIR::lower) Could not find binding for param \`${param.node.name}\``,
109
- severity: ErrorSeverity.Invariant,
110
- loc: param.node.loc ?? null,
111
- suggestions: null,
112
- });
108
+ builder.errors.pushDiagnostic(
109
+ CompilerDiagnostic.create({
110
+ category: 'Could not find binding',
111
+ description: `[BuildHIR] Could not find binding for param \`${param.node.name}\``,
112
+ severity: ErrorSeverity.Invariant,
113
+ suggestions: null,
114
+ }).withDetail({
115
+ kind: 'error',
116
+ loc: param.node.loc ?? null,
117
+ message: 'Could not find binding',
118
+ }),
119
+ );
120
return;
121
}
122
const place: Place = {
@@ -163,12 +170,18 @@ export function lower(
170
'Assignment',
171
);
172
} else {
166
- builder.errors.push({
167
- reason: `(BuildHIR::lower) Handle ${param.node.type} params`,
168
- severity: ErrorSeverity.Todo,
169
- loc: param.node.loc ?? null,
170
- suggestions: null,
171
- });
173
+ builder.errors.pushDiagnostic(
174
+ CompilerDiagnostic.create({
175
+ category: `Handle ${param.node.type} parameters`,
176
+ description: `[BuildHIR] Add support for ${param.node.type} parameters`,
177
+ severity: ErrorSeverity.Todo,
178
+ suggestions: null,
179
+ }).withDetail({
180
+ kind: 'error',
181
+ loc: param.node.loc ?? null,
182
+ message: 'Unsupported parameter type',
183
+ }),
184
+ );
185
}
186
});
187
@@ -188,13 +201,18 @@ export function lower(
201
lowerStatement(builder, body);
202
directives = body.get('directives').map(d => d.node.value.value);
203
} else {
191
- builder.errors.push({
192
- severity: ErrorSeverity.InvalidJS,
193
- reason: `Unexpected function body kind`,
194
- description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
195
- loc: body.node.loc ?? null,
196
- suggestions: null,
197
- });
204
+ builder.errors.pushDiagnostic(
205
+ CompilerDiagnostic.create({
206
+ severity: ErrorSeverity.InvalidJS,
207
+ category: `Unexpected function body kind`,
208
+ description: `Expected function body to be an expression or a block statement, got \`${body.type}\``,
209
+ suggestions: null,
210
+ }).withDetail({
211
+ kind: 'error',
212
+ loc: body.node.loc ?? null,
213
+ message: 'Expected a block statement or expression',
214
+ }),
215
+ );
216
}
217
218
if (builder.errors.hasErrors()) {
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts
+14
-11
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, Effect} from '..';
8
+import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
9
import {HIRFunction, IdentifierId, Place} from '../HIR';
10
import {
11
eachInstructionLValue,
@@ -28,16 +28,19 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
28
false,
29
);
30
if (reassignment !== null) {
31
- CompilerError.throwInvalidReact({
32
- reason:
33
- 'Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead',
34
- description:
35
- reassignment.identifier.name !== null &&
36
- reassignment.identifier.name.kind === 'named'
37
- ? `Variable \`${reassignment.identifier.name.value}\` cannot be reassigned after render`
38
- : '',
39
- loc: reassignment.loc,
40
- });
31
+ const errors = new CompilerError();
32
+ errors.pushDiagnostic(
33
+ CompilerDiagnostic.create({
34
+ severity: ErrorSeverity.InvalidReact,
35
+ category: 'Cannot reassign a variable after render completes',
36
+ description: `Reassigning ${reassignment.identifier.name != null && reassignment.identifier.name.kind === 'named' ? `variable \`${reassignment.identifier.name.value}\`` : 'a variable'} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead`,
37
+ }).withDetail({
38
+ kind: 'error',
39
+ loc: reassignment.loc,
40
+ message: 'Cannot reassign variable after render completes',
41
+ }),
42
+ );
43
+ throw errors;
44
}
45
}
46
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts
+19
-11
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, Effect, ErrorSeverity} from '..';
8
+import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
9
import {
10
FunctionEffect,
11
HIRFunction,
@@ -57,16 +57,24 @@ export function validateNoFreezingKnownMutableFunctions(
57
if (operand.effect === Effect.Freeze) {
58
const effect = contextMutationEffects.get(operand.identifier.id);
59
if (effect != null) {
60
- errors.push({
61
- reason: `This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`,
62
- loc: operand.loc,
63
- severity: ErrorSeverity.InvalidReact,
64
- });
65
- errors.push({
66
- reason: `The function modifies a local variable here`,
67
- loc: effect.loc,
68
- severity: ErrorSeverity.InvalidReact,
69
- });
60
+ errors.pushDiagnostic(
61
+ CompilerDiagnostic.create({
62
+ severity: ErrorSeverity.InvalidReact,
63
+ category: 'Cannot modify local variables after render completes',
64
+ description: `This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead`,
65
+ })
66
+ .withDetail({
67
+ kind: 'error',
68
+ loc: operand.loc,
69
+ message:
70
+ 'This function may (indirectly) reassign or modify local variables after render',
71
+ })
72
+ .withDetail({
73
+ kind: 'error',
74
+ loc: effect.loc,
75
+ message: 'This modifies a local variable',
76
+ }),
77
+ );
78
}
79
}
80
}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts
+17
-12
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, ErrorSeverity} from '..';
8
+import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
9
import {HIRFunction} from '../HIR';
10
import {getFunctionCallSignature} from '../Inference/InferReferenceEffects';
11
import {Result} from '../Utils/Result';
@@ -34,17 +34,22 @@ export function validateNoImpureFunctionsInRender(
34
callee.identifier.type,
35
);
36
if (signature != null && signature.impure === true) {
37
- errors.push({
38
- reason:
39
- 'Calling an impure function can produce unstable results. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
40
- description:
41
- signature.canonicalName != null
42
- ? `\`${signature.canonicalName}\` is an impure function whose results may change on every call`
43
- : null,
44
- severity: ErrorSeverity.InvalidReact,
45
- loc: callee.loc,
46
- suggestions: null,
47
- });
37
+ errors.pushDiagnostic(
38
+ CompilerDiagnostic.create({
39
+ category: 'Cannot call impure function during render',
40
+ description:
41
+ (signature.canonicalName != null
42
+ ? `\`${signature.canonicalName}\` is an impure function. `
43
+ : '') +
44
+ 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
45
+ severity: ErrorSeverity.InvalidReact,
46
+ suggestions: null,
47
+ }).withDetail({
48
+ kind: 'error',
49
+ loc: callee.loc,
50
+ message: 'Cannot call impure function',
51
+ }),
52
+ );
53
}
54
}
55
}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts
+12
-6
@@ -5,7 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, ErrorSeverity} from '..';
8
+import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
9
import {BlockId, HIRFunction} from '../HIR';
10
import {Result} from '../Utils/Result';
11
import {retainWhere} from '../Utils/utils';
@@ -34,11 +34,17 @@ export function validateNoJSXInTryStatement(
34
switch (value.kind) {
35
case 'JsxExpression':
36
case 'JsxFragment': {
37
- errors.push({
38
- severity: ErrorSeverity.InvalidReact,
39
- reason: `Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`,
40
- loc: value.loc,
41
- });
37
+ errors.pushDiagnostic(
38
+ CompilerDiagnostic.create({
39
+ severity: ErrorSeverity.InvalidReact,
40
+ category: 'Avoid constructing JSX within try/catch',
41
+ description: `React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`,
42
+ }).withDetail({
43
+ kind: 'error',
44
+ loc: value.loc,
45
+ message: 'Avoid constructing JSX within try/catch',
46
+ }),
47
+ );
48
break;
49
}
50
}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts
+20
-9
@@ -5,7 +5,11 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, ErrorSeverity} from '../CompilerError';
8
+import {
9
+ CompilerDiagnostic,
10
+ CompilerError,
11
+ ErrorSeverity,
12
+} from '../CompilerError';
13
import {
14
HIRFunction,
15
IdentifierId,
@@ -90,14 +94,21 @@ export function validateNoSetStateInEffects(
94
if (arg !== undefined && arg.kind === 'Identifier') {
95
const setState = setStateFunctions.get(arg.identifier.id);
96
if (setState !== undefined) {
93
- errors.push({
94
- reason:
95
- 'Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)',
96
- description: null,
97
- severity: ErrorSeverity.InvalidReact,
98
- loc: setState.loc,
99
- suggestions: null,
100
- });
97
+ errors.pushDiagnostic(
98
+ CompilerDiagnostic.create({
99
+ category:
100
+ 'Calling setState within an effect can trigger cascading renders',
101
+ description:
102
+ 'Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)',
103
+ severity: ErrorSeverity.InvalidReact,
104
+ suggestions: null,
105
+ }).withDetail({
106
+ kind: 'error',
107
+ loc: setState.loc,
108
+ message:
109
+ 'Avoid calling setState() in the top-level of an effect',
110
+ }),
111
+ );
112
}
113
}
114
}
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts
+33
-17
@@ -5,7 +5,11 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, ErrorSeverity} from '../CompilerError';
8
+import {
9
+ CompilerDiagnostic,
10
+ CompilerError,
11
+ ErrorSeverity,
12
+} from '../CompilerError';
13
import {HIRFunction, IdentifierId, isSetStateType} from '../HIR';
14
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
15
import {eachInstructionValueOperand} from '../HIR/visitors';
@@ -122,23 +126,35 @@ function validateNoSetStateInRenderImpl(
126
unconditionalSetStateFunctions.has(callee.identifier.id)
127
) {
128
if (activeManualMemoId !== null) {
125
- errors.push({
126
- reason:
127
- 'Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)',
128
- description: null,
129
- severity: ErrorSeverity.InvalidReact,
130
- loc: callee.loc,
131
- suggestions: null,
132
- });
129
+ errors.pushDiagnostic(
130
+ CompilerDiagnostic.create({
131
+ category:
132
+ 'Calling setState from useMemo may trigger an infinite loop',
133
+ description:
134
+ 'Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)',
135
+ severity: ErrorSeverity.InvalidReact,
136
+ suggestions: null,
137
+ }).withDetail({
138
+ kind: 'error',
139
+ loc: callee.loc,
140
+ message: 'Found setState() within useMemo()',
141
+ }),
142
+ );
143
} else if (unconditionalBlocks.has(block.id)) {
134
- errors.push({
135
- reason:
136
- 'This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)',
137
- description: null,
138
- severity: ErrorSeverity.InvalidReact,
139
- loc: callee.loc,
140
- suggestions: null,
141
- });
144
+ errors.pushDiagnostic(
145
+ CompilerDiagnostic.create({
146
+ category:
147
+ 'Calling setState during render may trigger an infinite loop',
148
+ description:
149
+ 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
150
+ severity: ErrorSeverity.InvalidReact,
151
+ suggestions: null,
152
+ }).withDetail({
153
+ kind: 'error',
154
+ loc: callee.loc,
155
+ message: 'Found setState() within useMemo()',
156
+ }),
157
+ );
158
}
159
}
160
break;
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts
+37
-16
@@ -5,7 +5,11 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {CompilerError, ErrorSeverity} from '..';
8
+import {
9
+ CompilerDiagnostic,
10
+ CompilerError,
11
+ ErrorSeverity,
12
+} from '../CompilerError';
13
import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR';
14
import {Result} from '../Utils/Result';
15
@@ -63,24 +67,41 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
67
}
68
69
if (body.loweredFunc.func.params.length > 0) {
66
- errors.push({
67
- severity: ErrorSeverity.InvalidReact,
68
- reason: 'useMemo callbacks may not accept any arguments',
69
- description: null,
70
- loc: body.loc,
71
- suggestions: null,
72
- });
70
+ const firstParam = body.loweredFunc.func.params[0];
71
+ const loc =
72
+ firstParam.kind === 'Identifier'
73
+ ? firstParam.loc
74
+ : firstParam.place.loc;
75
+ errors.pushDiagnostic(
76
+ CompilerDiagnostic.create({
77
+ severity: ErrorSeverity.InvalidReact,
78
+ category: 'useMemo() callbacks may not accept parameters',
79
+ description:
80
+ 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.',
81
+ suggestions: null,
82
+ }).withDetail({
83
+ kind: 'error',
84
+ loc,
85
+ message: '',
86
+ }),
87
+ );
88
}
89
90
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
76
- errors.push({
77
- severity: ErrorSeverity.InvalidReact,
78
- reason:
79
- 'useMemo callbacks may not be async or generator functions',
80
- description: null,
81
- loc: body.loc,
82
- suggestions: null,
83
- });
91
+ errors.pushDiagnostic(
92
+ CompilerDiagnostic.create({
93
+ severity: ErrorSeverity.InvalidReact,
94
+ category:
95
+ 'useMemo callbacks may not be async or generator functions',
96
+ description:
97
+ 'useMemo() callbacks are called once and must synchronously return a value',
98
+ suggestions: null,
99
+ }).withDetail({
100
+ kind: 'error',
101
+ loc: body.loc,
102
+ message: 'Async and generator functions are not supported',
103
+ }),
104
+ );
105
}
106
107
break;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-old-inference-false-positive-ref-validation-in-use-effect.expect.md
+6
-9
@@ -36,8 +36,10 @@ function Component() {
36
## Error
37
38
```
39
-Found 2 errors:
40
-Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
39
+Found 1 error:
40
+Error: Cannot modify local variables after render completes
41
+
42
+This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
43
44
error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
45
18 | );
@@ -51,24 +53,19 @@ error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:20:12
53
> 23 | }
54
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55
> 24 | }, [update]);
54
- | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
56
+ | ^^^^ This function may (indirectly) reassign or modify local variables after render
57
25 |
58
26 | return 'ok';
59
27 | }
60
59
-
60
-Error: The function modifies a local variable here
61
-
61
error.bug-old-inference-false-positive-ref-validation-in-use-effect.ts:14:6
62
12 | ...partialParams,
63
13 | };
64
> 14 | nextParams.param = 'value';
66
- | ^^^^^^^^^^ The function modifies a local variable here
65
+ | ^^^^^^^^^^ This modifies a local variable
66
15 | console.log(nextParams);
67
16 | },
68
17 | [params]
70
-
71
-
69
```
70
71
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.context-variable-only-chained-assign.expect.md
+3
-5
@@ -29,20 +29,18 @@ export const FIXTURE_ENTRYPOINT = {
29
30
```
31
Found 1 error:
32
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
32
+Error: Cannot reassign a variable after render completes
33
34
-Variable `x` cannot be reassigned after render.
34
+Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
35
36
error.context-variable-only-chained-assign.ts:10:19
37
8 | };
38
9 | const fn2 = () => {
39
> 10 | const copy2 = (x = 4);
40
- | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
40
+ | ^ Cannot reassign variable after render completes
41
11 | return [invoke(fn1), copy2, identity(copy2)];
42
12 | };
43
13 | return invoke(fn2);
44
-
45
-
44
```
45
46
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.declare-reassign-variable-in-function-declaration.expect.md
+3
-5
@@ -18,20 +18,18 @@ function Component() {
18
19
```
20
Found 1 error:
21
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
21
+Error: Cannot reassign a variable after render completes
22
23
-Variable `x` cannot be reassigned after render.
23
+Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25
error.declare-reassign-variable-in-function-declaration.ts:4:4
26
2 | let x = null;
27
3 | function foo() {
28
> 4 | x = 9;
29
- | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
29
+ | ^ Cannot reassign variable after render completes
30
5 | }
31
6 | const y = bar(foo);
32
7 | return <Child y={y} />;
33
-
34
-
33
```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.function-expression-references-variable-its-assigned-to.expect.md
+3
-5
@@ -16,20 +16,18 @@ function Component() {
16
17
```
18
Found 1 error:
19
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
19
+Error: Cannot reassign a variable after render completes
20
21
-Variable `callback` cannot be reassigned after render.
21
+Reassigning variable `callback` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
22
23
error.function-expression-references-variable-its-assigned-to.ts:3:4
24
1 | function Component() {
25
2 | let callback = () => {
26
> 3 | callback = null;
27
- | ^^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
27
+ | ^^^^^^^^ Cannot reassign variable after render completes
28
4 | };
29
5 | return <div onClick={callback} />;
30
6 | }
31
-
32
-
31
```
32
33
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ReactUseMemo-async-callback.expect.md
+3
-3
@@ -18,6 +18,8 @@ function component(a, b) {
18
Found 1 error:
19
Error: useMemo callbacks may not be async or generator functions
20
21
+useMemo() callbacks are called once and must synchronously return a value
22
+
23
error.invalid-ReactUseMemo-async-callback.ts:2:24
24
1 | function component(a, b) {
25
> 2 | let x = React.useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-ReactUseMemo-async-callback.ts:2:24
27
> 3 | await a;
28
| ^^^^^^^^^^^^
29
> 4 | }, []);
28
- | ^^^^ useMemo callbacks may not be async or generator functions
30
+ | ^^^^ Async and generator functions are not supported
31
5 | return x;
32
6 | }
33
7 |
32
-
33
-
34
```
35
36
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-conditional-setState-in-useMemo.expect.md
+7
-7
@@ -23,30 +23,30 @@ function Component({item, cond}) {
23
24
```
25
Found 2 errors:
26
-Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
26
+Error: Calling setState from useMemo may trigger an infinite loop
27
+
28
+Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)
29
30
error.invalid-conditional-setState-in-useMemo.ts:7:6
31
5 | useMemo(() => {
32
6 | if (cond) {
33
> 7 | setPrevItem(item);
32
- | ^^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
34
+ | ^^^^^^^^^^^ Found setState() within useMemo()
35
8 | setState(0);
36
9 | }
37
10 | }, [cond, key, init]);
38
+Error: Calling setState from useMemo may trigger an infinite loop
39
37
-
38
-Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
40
+Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)
41
42
error.invalid-conditional-setState-in-useMemo.ts:8:6
43
6 | if (cond) {
44
7 | setPrevItem(item);
45
> 8 | setState(0);
44
- | ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
46
+ | ^^^^^^^^ Found setState() within useMemo()
47
9 | }
48
10 | }, [cond, key, init]);
49
11 |
48
-
49
-
50
```
51
52
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-hook-function-argument-mutates-local-variable.expect.md
+6
-9
@@ -17,8 +17,10 @@ function useFoo() {
17
## Error
18
19
```
20
-Found 2 errors:
21
-Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
20
+Found 1 error:
21
+Error: Cannot modify local variables after render completes
22
+
23
+This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25
error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
26
3 | function useFoo() {
@@ -28,23 +30,18 @@ error.invalid-hook-function-argument-mutates-local-variable.ts:5:10
30
> 6 | cache.set('key', 'value');
31
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32
> 7 | });
31
- | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
33
+ | ^^^^ This function may (indirectly) reassign or modify local variables after render
34
8 | }
35
9 |
36
35
-
36
-Error: The function modifies a local variable here
37
-
37
error.invalid-hook-function-argument-mutates-local-variable.ts:6:4
38
4 | const cache = new Map();
39
5 | useHook(() => {
40
> 6 | cache.set('key', 'value');
42
- | ^^^^^ The function modifies a local variable here
41
+ | ^^^^^ This modifies a local variable
42
7 | });
43
8 | }
44
9 |
46
-
47
-
45
```
46
47
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-nested-function-reassign-local-variable-in-effect.expect.md
+3
-5
@@ -47,20 +47,18 @@ function Component() {
47
48
```
49
Found 1 error:
50
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
50
+Error: Cannot reassign a variable after render completes
51
52
-Variable `local` cannot be reassigned after render.
52
+Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
53
54
error.invalid-nested-function-reassign-local-variable-in-effect.ts:7:6
55
5 | // Create the reassignment function inside another function, then return it
56
6 | const reassignLocal = newValue => {
57
> 7 | local = newValue;
58
- | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
58
+ | ^^^^^ Cannot reassign variable after render completes
59
8 | };
60
9 | return reassignLocal;
61
10 | };
62
-
63
-
62
```
63
64
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-pass-mutable-function-as-prop.expect.md
+6
-9
@@ -17,30 +17,27 @@ function Component() {
17
## Error
18
19
```
20
-Found 2 errors:
21
-Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
20
+Found 1 error:
21
+Error: Cannot modify local variables after render completes
22
+
23
+This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25
error.invalid-pass-mutable-function-as-prop.ts:7:18
26
5 | cache.set('key', 'value');
27
6 | };
28
> 7 | return <Foo fn={fn} />;
27
- | ^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
29
+ | ^^ This function may (indirectly) reassign or modify local variables after render
30
8 | }
31
9 |
32
31
-
32
-Error: The function modifies a local variable here
33
-
33
error.invalid-pass-mutable-function-as-prop.ts:5:4
34
3 | const cache = new Map();
35
4 | const fn = () => {
36
> 5 | cache.set('key', 'value');
38
- | ^^^^^ The function modifies a local variable here
37
+ | ^^^^^ This modifies a local variable
38
6 | };
39
7 | return <Foo fn={fn} />;
40
8 | }
42
-
43
-
41
```
42
43
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-in-hook-return-value.expect.md
+3
-5
@@ -16,20 +16,18 @@ function useFoo() {
16
17
```
18
Found 1 error:
19
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
19
+Error: Cannot reassign a variable after render completes
20
21
-Variable `x` cannot be reassigned after render.
21
+Reassigning variable `x` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
22
23
error.invalid-reassign-local-in-hook-return-value.ts:4:4
24
2 | let x = 0;
25
3 | return value => {
26
> 4 | x = value;
27
- | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
27
+ | ^ Cannot reassign variable after render completes
28
5 | };
29
6 | }
30
7 |
31
-
32
-
31
```
32
33
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-effect.expect.md
+3
-5
@@ -48,20 +48,18 @@ function Component() {
48
49
```
50
Found 1 error:
51
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
51
+Error: Cannot reassign a variable after render completes
52
53
-Variable `local` cannot be reassigned after render.
53
+Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
54
55
error.invalid-reassign-local-variable-in-effect.ts:7:4
56
5 |
57
6 | const reassignLocal = newValue => {
58
> 7 | local = newValue;
59
- | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
59
+ | ^^^^^ Cannot reassign variable after render completes
60
8 | };
61
9 |
62
10 | const onMount = newValue => {
63
-
64
-
63
```
64
65
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-hook-argument.expect.md
+3
-5
@@ -49,20 +49,18 @@ function Component() {
49
50
```
51
Found 1 error:
52
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
52
+Error: Cannot reassign a variable after render completes
53
54
-Variable `local` cannot be reassigned after render.
54
+Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
55
56
error.invalid-reassign-local-variable-in-hook-argument.ts:8:4
57
6 |
58
7 | const reassignLocal = newValue => {
59
> 8 | local = newValue;
60
- | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
60
+ | ^^^^^ Cannot reassign variable after render completes
61
9 | };
62
10 |
63
11 | const callback = newValue => {
64
-
65
-
64
```
65
66
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-local-variable-in-jsx-callback.expect.md
+3
-5
@@ -42,20 +42,18 @@ function Component() {
42
43
```
44
Found 1 error:
45
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
45
+Error: Cannot reassign a variable after render completes
46
47
-Variable `local` cannot be reassigned after render.
47
+Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
48
49
error.invalid-reassign-local-variable-in-jsx-callback.ts:5:4
50
3 |
51
4 | const reassignLocal = newValue => {
52
> 5 | local = newValue;
53
- | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
53
+ | ^^^^^ Cannot reassign variable after render completes
54
6 | };
55
7 |
56
8 | const onClick = newValue => {
57
-
58
-
57
```
58
59
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-return-mutable-function-from-hook.expect.md
+6
-9
@@ -19,8 +19,10 @@ function useFoo() {
19
## Error
20
21
```
22
-Found 2 errors:
23
-Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
22
+Found 1 error:
23
+Error: Cannot modify local variables after render completes
24
+
25
+This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
26
27
error.invalid-return-mutable-function-from-hook.ts:7:9
28
5 | useHook(); // for inference to kick in
@@ -30,23 +32,18 @@ error.invalid-return-mutable-function-from-hook.ts:7:9
32
> 8 | cache.set('key', 'value');
33
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34
> 9 | };
33
- | ^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
35
+ | ^^^^ This function may (indirectly) reassign or modify local variables after render
36
10 | }
37
11 |
38
37
-
38
-Error: The function modifies a local variable here
39
-
39
error.invalid-return-mutable-function-from-hook.ts:8:4
40
6 | const cache = new Map();
41
7 | return () => {
42
> 8 | cache.set('key', 'value');
44
- | ^^^^^ The function modifies a local variable here
43
+ | ^^^^^ This modifies a local variable
44
9 | };
45
10 | }
46
11 |
48
-
49
-
47
```
48
49
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo-indirect-useCallback.expect.md
+4
-4
@@ -27,18 +27,18 @@ function useKeyedState({key, init}) {
27
28
```
29
Found 1 error:
30
-Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
30
+Error: Calling setState from useMemo may trigger an infinite loop
31
+
32
+Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)
33
34
error.invalid-setState-in-useMemo-indirect-useCallback.ts:13:4
35
11 |
36
12 | useMemo(() => {
37
> 13 | fn();
36
- | ^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
38
+ | ^^ Found setState() within useMemo()
39
14 | }, [key, init]);
40
15 |
41
16 | return state;
40
-
41
-
42
```
43
44
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-setState-in-useMemo.expect.md
+7
-7
@@ -21,30 +21,30 @@ function useKeyedState({key, init}) {
21
22
```
23
Found 2 errors:
24
-Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
24
+Error: Calling setState from useMemo may trigger an infinite loop
25
+
26
+Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)
27
28
error.invalid-setState-in-useMemo.ts:6:4
29
4 |
30
5 | useMemo(() => {
31
> 6 | setPrevKey(key);
30
- | ^^^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
32
+ | ^^^^^^^^^^ Found setState() within useMemo()
33
7 | setState(init);
34
8 | }, [key, init]);
35
9 |
36
+Error: Calling setState from useMemo may trigger an infinite loop
37
35
-
36
-Error: Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
38
+Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)
39
40
error.invalid-setState-in-useMemo.ts:7:4
41
5 | useMemo(() => {
42
6 | setPrevKey(key);
43
> 7 | setState(init);
42
- | ^^^^^^^^ Calling setState from useMemo may trigger an infinite loop. (https://react.dev/reference/react/useState)
44
+ | ^^^^^^^^ Found setState() within useMemo()
45
8 | }, [key, init]);
46
9 |
47
10 | return state;
46
-
47
-
48
```
49
50
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md
+6
-9
@@ -47,8 +47,10 @@ hook useMemoMap<TInput: interface {}, TOutput>(
47
## Error
48
49
```
50
-Found 2 errors:
51
-Error: This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
50
+Found 1 error:
51
+Error: Cannot modify local variables after render completes
52
+
53
+This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
54
55
undefined:21:9
56
19 | map: TInput => TOutput
@@ -86,23 +88,18 @@ undefined:21:9
88
> 36 | };
89
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90
> 37 | }, [map]);
89
- | ^^^^^^^^^^^^ This argument is a function which may reassign or mutate local variables after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead
91
+ | ^^^^^^^^^^^^ This function may (indirectly) reassign or modify local variables after render
92
38 | }
93
39 |
94
93
-
94
-Error: The function modifies a local variable here
95
-
95
undefined:33:8
96
31 | if (output == null) {
97
32 | output = map(input);
98
> 33 | cache.set(input, output);
100
- | ^^^^^ The function modifies a local variable here
99
+ | ^^^^^ This modifies a local variable
100
34 | }
101
35 | return output;
102
36 | };
104
-
105
-
103
```
104
105
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unconditional-set-state-in-render.expect.md
+7
-7
@@ -20,30 +20,30 @@ function Component(props) {
20
21
```
22
Found 2 errors:
23
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
23
+Error: Calling setState during render may trigger an infinite loop
24
+
25
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
26
27
error.invalid-unconditional-set-state-in-render.ts:6:2
28
4 | const aliased = setX;
29
5 |
30
> 6 | setX(1);
29
- | ^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
31
+ | ^^^^ Found setState() within useMemo()
32
7 | aliased(2);
33
8 |
34
9 | return x;
35
+Error: Calling setState during render may trigger an infinite loop
36
34
-
35
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
37
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
38
39
error.invalid-unconditional-set-state-in-render.ts:7:2
40
5 |
41
6 | setX(1);
42
> 7 | aliased(2);
41
- | ^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
43
+ | ^^^^^^^ Found setState() within useMemo()
44
8 |
45
9 | return x;
46
10 | }
45
-
46
-
47
```
48
49
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useMemo-async-callback.expect.md
+3
-3
@@ -18,6 +18,8 @@ function component(a, b) {
18
Found 1 error:
19
Error: useMemo callbacks may not be async or generator functions
20
21
+useMemo() callbacks are called once and must synchronously return a value
22
+
23
error.invalid-useMemo-async-callback.ts:2:18
24
1 | function component(a, b) {
25
> 2 | let x = useMemo(async () => {
@@ -25,12 +27,10 @@ error.invalid-useMemo-async-callback.ts:2:18
27
> 3 | await a;
28
| ^^^^^^^^^^^^
29
> 4 | }, []);
28
- | ^^^^ useMemo callbacks may not be async or generator functions
30
+ | ^^^^ Async and generator functions are not supported
31
5 | return x;
32
6 | }
33
7 |
32
-
33
-
34
```
35
36
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-useMemo-callback-args.expect.md
+4
-4
@@ -14,17 +14,17 @@ function component(a, b) {
14
15
```
16
Found 1 error:
17
-Error: useMemo callbacks may not accept any arguments
17
+Error: useMemo() callbacks may not accept parameters
18
+
19
+useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.
20
21
error.invalid-useMemo-callback-args.ts:2:18
22
1 | function component(a, b) {
23
> 2 | let x = useMemo(c => a, []);
22
- | ^^^^^^ useMemo callbacks may not accept any arguments
24
+ | ^
25
3 | return x;
26
4 | }
27
5 |
26
-
27
-
28
```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.mutable-range-shared-inner-outer-function.expect.md
+3
-5
@@ -33,20 +33,18 @@ export const FIXTURE_ENTRYPOINT = {
33
34
```
35
Found 1 error:
36
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
36
+Error: Cannot reassign a variable after render completes
37
38
-Variable `a` cannot be reassigned after render.
38
+Reassigning variable `a` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
39
40
error.mutable-range-shared-inner-outer-function.ts:8:6
41
6 | const f = () => {
42
7 | if (cond) {
43
> 8 | a = {};
44
- | ^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
44
+ | ^ Cannot reassign variable after render completes
45
9 | b = [];
46
10 | } else {
47
11 | a = {};
48
-
49
-
48
```
49
50
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-function-expression-references-later-variable-declaration.expect.md
+3
-5
@@ -18,20 +18,18 @@ function Component() {
18
19
```
20
Found 1 error:
21
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
21
+Error: Cannot reassign a variable after render completes
22
23
-Variable `onClick` cannot be reassigned after render.
23
+Reassigning variable `onClick` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
24
25
error.todo-function-expression-references-later-variable-declaration.ts:3:4
26
1 | function Component() {
27
2 | let callback = () => {
28
> 3 | onClick = () => {};
29
- | ^^^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
29
+ | ^^^^^^^ Cannot reassign variable after render completes
30
4 | };
31
5 | let onClick;
32
6 |
33
-
34
-
33
```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop-break.expect.md
+4
-4
@@ -23,18 +23,18 @@ function Component(props) {
23
24
```
25
Found 1 error:
26
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
26
+Error: Calling setState during render may trigger an infinite loop
27
+
28
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
29
30
error.unconditional-set-state-in-render-after-loop-break.ts:11:2
31
9 | }
32
10 | }
33
> 11 | setState(true);
32
- | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
34
+ | ^^^^^^^^ Found setState() within useMemo()
35
12 | return state;
36
13 | }
37
14 |
36
-
37
-
38
```
39
40
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-after-loop.expect.md
+4
-4
@@ -18,18 +18,18 @@ function Component(props) {
18
19
```
20
Found 1 error:
21
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
21
+Error: Calling setState during render may trigger an infinite loop
22
+
23
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
24
25
error.unconditional-set-state-in-render-after-loop.ts:6:2
26
4 | for (const _ of props) {
27
5 | }
28
> 6 | setState(true);
27
- | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
29
+ | ^^^^^^^^ Found setState() within useMemo()
30
7 | return state;
31
8 | }
32
9 |
31
-
32
-
33
```
34
35
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-in-render-with-loop-throw.expect.md
+4
-4
@@ -23,18 +23,18 @@ function Component(props) {
23
24
```
25
Found 1 error:
26
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
26
+Error: Calling setState during render may trigger an infinite loop
27
+
28
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
29
30
error.unconditional-set-state-in-render-with-loop-throw.ts:11:2
31
9 | }
32
10 | }
33
> 11 | setState(true);
32
- | ^^^^^^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
34
+ | ^^^^^^^^ Found setState() within useMemo()
35
12 | return state;
36
13 | }
37
14 |
36
-
37
-
38
```
39
40
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-lambda.expect.md
+4
-4
@@ -21,18 +21,18 @@ function Component(props) {
21
22
```
23
Found 1 error:
24
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
24
+Error: Calling setState during render may trigger an infinite loop
25
+
26
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
27
28
error.unconditional-set-state-lambda.ts:8:2
29
6 | setX(1);
30
7 | };
31
> 8 | foo();
30
- | ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
32
+ | ^^^ Found setState() within useMemo()
33
9 |
34
10 | return [x];
35
11 | }
34
-
35
-
36
```
37
38
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.unconditional-set-state-nested-function-expressions.expect.md
+4
-4
@@ -29,18 +29,18 @@ function Component(props) {
29
30
```
31
Found 1 error:
32
-Error: This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
32
+Error: Calling setState during render may trigger an infinite loop
33
+
34
+Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)
35
36
error.unconditional-set-state-nested-function-expressions.ts:16:2
37
14 | bar();
38
15 | };
39
> 16 | baz();
38
- | ^^^ This is an unconditional set state during render, which will trigger an infinite loop. (https://react.dev/reference/react/useState)
40
+ | ^^^ Found setState() within useMemo()
41
17 |
42
18 | return [x];
43
19 | }
42
-
43
-
44
```
45
46
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md
+1
-1
@@ -65,7 +65,7 @@ function Component(props) {
65
## Logs
66
67
```
68
-{"kind":"CompileError","detail":{"options":{"reason":"Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","description":null,"severity":"InvalidReact","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"}}},"fnLoc":null}
68
+{"kind":"CompileError","detail":{"options":{"severity":"InvalidReact","category":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
69
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":91},"end":{"line":17,"column":1,"index":298},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
70
```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md
+1
-1
@@ -42,7 +42,7 @@ function Component(props) {
42
## Logs
43
44
```
45
-{"kind":"CompileError","detail":{"options":{"reason":"Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","description":null,"severity":"InvalidReact","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"}}},"fnLoc":null}
45
+{"kind":"CompileError","detail":{"options":{"severity":"InvalidReact","category":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
46
{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":49},"end":{"line":10,"column":1,"index":160},"filename":"invalid-jsx-in-try-with-catch.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
47
```
48
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md
+1
-1
@@ -65,7 +65,7 @@ function _temp(s) {
65
## Logs
66
67
```
68
-{"kind":"CompileError","detail":{"options":{"reason":"Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"}}},"fnLoc":null}
68
+{"kind":"CompileError","detail":{"options":{"category":"Calling setState within an effect can trigger cascading renders","description":"Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() in the top-level of an effect"}]}},"fnLoc":null}
69
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":16,"column":1,"index":293},"filename":"invalid-setState-in-useEffect-transitive.ts"},"fnName":"Component","memoSlots":2,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
70
```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md
+1
-1
@@ -45,7 +45,7 @@ function _temp(s) {
45
## Logs
46
47
```
48
-{"kind":"CompileError","detail":{"options":{"reason":"Calling setState directly within a useEffect causes cascading renders and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","description":null,"severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"}}},"fnLoc":null}
48
+{"kind":"CompileError","detail":{"options":{"category":"Calling setState within an effect can trigger cascading renders","description":"Calling setState directly within a useEffect causes cascading renders that can hurt performance, and is not recommended. Consider alternatives to useEffect. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() in the top-level of an effect"}]}},"fnLoc":null}
49
{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":10,"column":1,"index":225},"filename":"invalid-setState-in-useEffect.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
50
```
51
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/error.invalid-reassign-local-variable-in-jsx-callback.expect.md
+3
-5
@@ -43,20 +43,18 @@ function Component() {
43
44
```
45
Found 1 error:
46
-Error: Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
46
+Error: Cannot reassign a variable after render completes
47
48
-Variable `local` cannot be reassigned after render.
48
+Reassigning variable `local` after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
49
50
error.invalid-reassign-local-variable-in-jsx-callback.ts:6:4
51
4 |
52
5 | const reassignLocal = newValue => {
53
> 6 | local = newValue;
54
- | ^^^^^ Reassigning a variable after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead
54
+ | ^^^^^ Cannot reassign variable after render completes
55
7 | };
56
8 |
57
9 | const onClick = newValue => {
58
-
59
-
58
```
59
60
\ No newline at end of file