[compiler] Update ValidateNoDerivedComputationsInEffects_exp to log the error instead of throwing (#34972)
Summary: TSIA Simple change to log errors in Pipeline.ts instead of throwing in the validation Test Plan: updated snap tests --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34972). * #35044 * #35020 * #34973 * __->__ #34972
Jorge Cabiedes committed
Nov 10, 2025 at 12:16 UTC
72961203966a2f1d34dfca089e0a94a94ead7658
44 files changed
+893
-592
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+1
-1
@@ -277,7 +277,7 @@ function runWithEnvironment(
277
}
278
279
if (env.config.validateNoDerivedComputationsInEffects_exp) {
280
- validateNoDerivedComputationsInEffects_exp(hir);
280
+ env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
281
}
282
283
if (env.config.validateNoSetStateInEffects) {
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects_exp.ts
+3
-4
@@ -5,6 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
+import {Result} from '../Utils/Result';
9
import {CompilerDiagnostic, CompilerError, Effect} from '..';
10
import {ErrorCategory} from '../CompilerError';
11
import {
@@ -173,7 +174,7 @@ function isNamedIdentifier(place: Place): place is Place & {
174
*/
175
export function validateNoDerivedComputationsInEffects_exp(
176
fn: HIRFunction,
176
-): void {
177
+): Result<void, CompilerError> {
178
const functions: Map<IdentifierId, FunctionExpression> = new Map();
179
const derivationCache = new DerivationCache();
180
const errors = new CompilerError();
@@ -236,9 +237,7 @@ export function validateNoDerivedComputationsInEffects_exp(
237
validateEffect(effect, context);
238
}
239
239
- if (errors.hasAnyErrors()) {
240
- throw errors;
241
- }
240
+ return errors.asResult();
241
}
242
243
function recordPhiDerivations(
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md
new
+86
@@ -0,0 +1,86 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+function Component({value, enabled}) {
9
+ const [localValue, setLocalValue] = useState('');
10
+
11
+ useEffect(() => {
12
+ if (enabled) {
13
+ setLocalValue(value);
14
+ } else {
15
+ setLocalValue('disabled');
16
+ }
17
+ }, [value, enabled]);
18
+
19
+ return <div>{localValue}</div>;
20
+}
21
+
22
+export const FIXTURE_ENTRYPOINT = {
23
+ fn: Component,
24
+ params: [{value: 'test', enabled: true}],
25
+};
26
+
27
+```
28
+
29
+## Code
30
+
31
+```javascript
32
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
33
+import { useEffect, useState } from "react";
34
+
35
+function Component(t0) {
36
+ const $ = _c(6);
37
+ const { value, enabled } = t0;
38
+ const [localValue, setLocalValue] = useState("");
39
+ let t1;
40
+ let t2;
41
+ if ($[0] !== enabled || $[1] !== value) {
42
+ t1 = () => {
43
+ if (enabled) {
44
+ setLocalValue(value);
45
+ } else {
46
+ setLocalValue("disabled");
47
+ }
48
+ };
49
+
50
+ t2 = [value, enabled];
51
+ $[0] = enabled;
52
+ $[1] = value;
53
+ $[2] = t1;
54
+ $[3] = t2;
55
+ } else {
56
+ t1 = $[2];
57
+ t2 = $[3];
58
+ }
59
+ useEffect(t1, t2);
60
+ let t3;
61
+ if ($[4] !== localValue) {
62
+ t3 = <div>{localValue}</div>;
63
+ $[4] = localValue;
64
+ $[5] = t3;
65
+ } else {
66
+ t3 = $[5];
67
+ }
68
+ return t3;
69
+}
70
+
71
+export const FIXTURE_ENTRYPOINT = {
72
+ fn: Component,
73
+ params: [{ value: "test", enabled: true }],
74
+};
75
+
76
+```
77
+
78
+## Logs
79
+
80
+```
81
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":6,"index":244},"end":{"line":9,"column":19,"index":257},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
82
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
83
+```
84
+
85
+### Eval output
86
+(kind: ok) <div>test</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({value, enabled}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.expect.md
new
+78
@@ -0,0 +1,78 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+export default function Component({input = 'empty'}) {
9
+ const [currInput, setCurrInput] = useState(input);
10
+ const localConst = 'local const';
11
+
12
+ useEffect(() => {
13
+ setCurrInput(input + localConst);
14
+ }, [input, localConst]);
15
+
16
+ return <div>{currInput}</div>;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{input: 'test'}],
22
+};
23
+
24
+```
25
+
26
+## Code
27
+
28
+```javascript
29
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
30
+import { useEffect, useState } from "react";
31
+
32
+export default function Component(t0) {
33
+ const $ = _c(5);
34
+ const { input: t1 } = t0;
35
+ const input = t1 === undefined ? "empty" : t1;
36
+ const [currInput, setCurrInput] = useState(input);
37
+ let t2;
38
+ let t3;
39
+ if ($[0] !== input) {
40
+ t2 = () => {
41
+ setCurrInput(input + "local const");
42
+ };
43
+ t3 = [input, "local const"];
44
+ $[0] = input;
45
+ $[1] = t2;
46
+ $[2] = t3;
47
+ } else {
48
+ t2 = $[1];
49
+ t3 = $[2];
50
+ }
51
+ useEffect(t2, t3);
52
+ let t4;
53
+ if ($[3] !== currInput) {
54
+ t4 = <div>{currInput}</div>;
55
+ $[3] = currInput;
56
+ $[4] = t4;
57
+ } else {
58
+ t4 = $[4];
59
+ }
60
+ return t4;
61
+}
62
+
63
+export const FIXTURE_ENTRYPOINT = {
64
+ fn: Component,
65
+ params: [{ input: "test" }],
66
+};
67
+
68
+```
69
+
70
+## Logs
71
+
72
+```
73
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [input]\n\nData Flow Tree:\n└── input (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":276},"end":{"line":9,"column":16,"index":288},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
74
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":372},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
75
+```
76
+
77
+### Eval output
78
+(kind: ok) <div>testlocal const</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
export default function Component({input = 'empty'}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.expect.md
new
+77
@@ -0,0 +1,77 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+
7
+import {useEffect, useState} from 'react';
8
+
9
+function Component({shouldChange}) {
10
+ const [count, setCount] = useState(0);
11
+
12
+ useEffect(() => {
13
+ if (shouldChange) {
14
+ setCount(count + 1);
15
+ }
16
+ }, [count]);
17
+
18
+ return <div>{count}</div>;
19
+}
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
27
+
28
+import { useEffect, useState } from "react";
29
+
30
+function Component(t0) {
31
+ const $ = _c(7);
32
+ const { shouldChange } = t0;
33
+ const [count, setCount] = useState(0);
34
+ let t1;
35
+ if ($[0] !== count || $[1] !== shouldChange) {
36
+ t1 = () => {
37
+ if (shouldChange) {
38
+ setCount(count + 1);
39
+ }
40
+ };
41
+ $[0] = count;
42
+ $[1] = shouldChange;
43
+ $[2] = t1;
44
+ } else {
45
+ t1 = $[2];
46
+ }
47
+ let t2;
48
+ if ($[3] !== count) {
49
+ t2 = [count];
50
+ $[3] = count;
51
+ $[4] = t2;
52
+ } else {
53
+ t2 = $[4];
54
+ }
55
+ useEffect(t1, t2);
56
+ let t3;
57
+ if ($[5] !== count) {
58
+ t3 = <div>{count}</div>;
59
+ $[5] = count;
60
+ $[6] = t3;
61
+ } else {
62
+ t3 = $[6];
63
+ }
64
+ return t3;
65
+}
66
+
67
+```
68
+
69
+## Logs
70
+
71
+```
72
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [count]\n\nData Flow Tree:\n└── count (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":6,"index":237},"end":{"line":10,"column":14,"index":245},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
73
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":15,"column":1,"index":310},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
74
+```
75
+
76
+### Eval output
77
+(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
3
import {useEffect, useState} from 'react';
4
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.expect.md
new
+115
@@ -0,0 +1,115 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+function Component({firstName}) {
9
+ const [lastName, setLastName] = useState('Doe');
10
+ const [fullName, setFullName] = useState('John');
11
+
12
+ const middleName = 'D.';
13
+
14
+ useEffect(() => {
15
+ setFullName(firstName + ' ' + middleName + ' ' + lastName);
16
+ }, [firstName, middleName, lastName]);
17
+
18
+ return (
19
+ <div>
20
+ <input value={lastName} onChange={e => setLastName(e.target.value)} />
21
+ <div>{fullName}</div>
22
+ </div>
23
+ );
24
+}
25
+
26
+export const FIXTURE_ENTRYPOINT = {
27
+ fn: Component,
28
+ params: [{firstName: 'John'}],
29
+};
30
+
31
+```
32
+
33
+## Code
34
+
35
+```javascript
36
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
37
+import { useEffect, useState } from "react";
38
+
39
+function Component(t0) {
40
+ const $ = _c(12);
41
+ const { firstName } = t0;
42
+ const [lastName, setLastName] = useState("Doe");
43
+ const [fullName, setFullName] = useState("John");
44
+ let t1;
45
+ let t2;
46
+ if ($[0] !== firstName || $[1] !== lastName) {
47
+ t1 = () => {
48
+ setFullName(firstName + " " + "D." + " " + lastName);
49
+ };
50
+ t2 = [firstName, "D.", lastName];
51
+ $[0] = firstName;
52
+ $[1] = lastName;
53
+ $[2] = t1;
54
+ $[3] = t2;
55
+ } else {
56
+ t1 = $[2];
57
+ t2 = $[3];
58
+ }
59
+ useEffect(t1, t2);
60
+ let t3;
61
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
62
+ t3 = (e) => setLastName(e.target.value);
63
+ $[4] = t3;
64
+ } else {
65
+ t3 = $[4];
66
+ }
67
+ let t4;
68
+ if ($[5] !== lastName) {
69
+ t4 = <input value={lastName} onChange={t3} />;
70
+ $[5] = lastName;
71
+ $[6] = t4;
72
+ } else {
73
+ t4 = $[6];
74
+ }
75
+ let t5;
76
+ if ($[7] !== fullName) {
77
+ t5 = <div>{fullName}</div>;
78
+ $[7] = fullName;
79
+ $[8] = t5;
80
+ } else {
81
+ t5 = $[8];
82
+ }
83
+ let t6;
84
+ if ($[9] !== t4 || $[10] !== t5) {
85
+ t6 = (
86
+ <div>
87
+ {t4}
88
+ {t5}
89
+ </div>
90
+ );
91
+ $[9] = t4;
92
+ $[10] = t5;
93
+ $[11] = t6;
94
+ } else {
95
+ t6 = $[11];
96
+ }
97
+ return t6;
98
+}
99
+
100
+export const FIXTURE_ENTRYPOINT = {
101
+ fn: Component,
102
+ params: [{ firstName: "John" }],
103
+};
104
+
105
+```
106
+
107
+## Logs
108
+
109
+```
110
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [firstName]\nState: [lastName]\n\nData Flow Tree:\n├── firstName (Prop)\n└── lastName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":297},"end":{"line":11,"column":15,"index":308},"filename":"derived-state-from-prop-local-state-and-component-scope.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
111
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":20,"column":1,"index":542},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
112
+```
113
+
114
+### Eval output
115
+(kind: ok) <div><input value="Doe"><div>John D. Doe</div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({firstName}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-call-outside-effect-no-error.expect.md
+8
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState} from 'react';
7
8
function Component({initialName}) {
@@ -29,7 +29,7 @@ export const FIXTURE_ENTRYPOINT = {
29
## Code
30
31
```javascript
32
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
32
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
33
import { useEffect, useState } from "react";
34
35
function Component(t0) {
@@ -79,6 +79,12 @@ export const FIXTURE_ENTRYPOINT = {
79
};
80
81
```
82
+
83
+## Logs
84
+
85
+```
86
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":16,"column":1,"index":359},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
87
+```
88
89
### Eval output
90
(kind: ok) <div><input value="John"></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-call-outside-effect-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({initialName}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.expect.md
new
+57
@@ -0,0 +1,57 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp
6
+
7
+function Component({value}) {
8
+ const [checked, setChecked] = useState('');
9
+
10
+ useEffect(() => {
11
+ setChecked(value === '' ? [] : value.split(','));
12
+ }, [value]);
13
+
14
+ return <div>{checked}</div>;
15
+}
16
+
17
+```
18
+
19
+## Code
20
+
21
+```javascript
22
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
23
+
24
+function Component(t0) {
25
+ const $ = _c(5);
26
+ const { value } = t0;
27
+ const [checked, setChecked] = useState("");
28
+ let t1;
29
+ let t2;
30
+ if ($[0] !== value) {
31
+ t1 = () => {
32
+ setChecked(value === "" ? [] : value.split(","));
33
+ };
34
+ t2 = [value];
35
+ $[0] = value;
36
+ $[1] = t1;
37
+ $[2] = t2;
38
+ } else {
39
+ t1 = $[1];
40
+ t2 = $[2];
41
+ }
42
+ useEffect(t1, t2);
43
+ let t3;
44
+ if ($[3] !== checked) {
45
+ t3 = <div>{checked}</div>;
46
+ $[3] = checked;
47
+ $[4] = t3;
48
+ } else {
49
+ t3 = $[4];
50
+ }
51
+ return t3;
52
+}
53
+
54
+```
55
+
56
+### Eval output
57
+(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js
renamed
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-used-outside-effect-no-error.expect.md
+9
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState} from 'react';
7
8
function MockComponent({onSet}) {
@@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = {
28
## Code
29
30
```javascript
31
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
31
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
32
import { useEffect, useState } from "react";
33
34
function MockComponent(t0) {
@@ -80,6 +80,13 @@ export const FIXTURE_ENTRYPOINT = {
80
};
81
82
```
83
+
84
+## Logs
85
+
86
+```
87
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":6,"column":1,"index":211},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
88
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":213},"end":{"line":15,"column":1,"index":402},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
89
+```
90
91
### Eval output
92
(kind: ok) <div>Mock Component</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-used-outside-effect-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function MockComponent({onSet}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.expect.md
new
+78
@@ -0,0 +1,78 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+function Component({value}) {
9
+ const [localValue, setLocalValue] = useState('');
10
+
11
+ useEffect(() => {
12
+ setLocalValue(value);
13
+ document.title = `Value: ${value}`;
14
+ }, [value]);
15
+
16
+ return <div>{localValue}</div>;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{value: 'test'}],
22
+};
23
+
24
+```
25
+
26
+## Code
27
+
28
+```javascript
29
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
30
+import { useEffect, useState } from "react";
31
+
32
+function Component(t0) {
33
+ const $ = _c(5);
34
+ const { value } = t0;
35
+ const [localValue, setLocalValue] = useState("");
36
+ let t1;
37
+ let t2;
38
+ if ($[0] !== value) {
39
+ t1 = () => {
40
+ setLocalValue(value);
41
+ document.title = `Value: ${value}`;
42
+ };
43
+ t2 = [value];
44
+ $[0] = value;
45
+ $[1] = t1;
46
+ $[2] = t2;
47
+ } else {
48
+ t1 = $[1];
49
+ t2 = $[2];
50
+ }
51
+ useEffect(t1, t2);
52
+ let t3;
53
+ if ($[3] !== localValue) {
54
+ t3 = <div>{localValue}</div>;
55
+ $[3] = localValue;
56
+ $[4] = t3;
57
+ } else {
58
+ t3 = $[4];
59
+ }
60
+ return t3;
61
+}
62
+
63
+export const FIXTURE_ENTRYPOINT = {
64
+ fn: Component,
65
+ params: [{ value: "test" }],
66
+};
67
+
68
+```
69
+
70
+## Logs
71
+
72
+```
73
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [value]\n\nData Flow Tree:\n└── value (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":8,"column":4,"index":214},"end":{"line":8,"column":17,"index":227},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
74
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":13,"column":1,"index":327},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
75
+```
76
+
77
+### Eval output
78
+(kind: ok) <div>test</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({value}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.expect.md
+8
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState, useRef} from 'react';
7
8
export default function Component({test}) {
@@ -27,7 +27,7 @@ export const FIXTURE_ENTRYPOINT = {
27
## Code
28
29
```javascript
30
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
30
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
31
import { useEffect, useState, useRef } from "react";
32
33
export default function Component(t0) {
@@ -68,6 +68,12 @@ export const FIXTURE_ENTRYPOINT = {
68
};
69
70
```
71
+
72
+## Logs
73
+
74
+```
75
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":14,"column":1,"index":328},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
76
+```
77
78
### Eval output
79
(kind: ok) nulltestString
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState, useRef} from 'react';
3
4
export default function Component({test}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.expect.md
new
+93
@@ -0,0 +1,93 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+function Component({propValue}) {
9
+ const [value, setValue] = useState(null);
10
+
11
+ function localFunction() {
12
+ console.log('local function');
13
+ }
14
+
15
+ useEffect(() => {
16
+ setValue(propValue);
17
+ localFunction();
18
+ }, [propValue]);
19
+
20
+ return <div>{value}</div>;
21
+}
22
+
23
+export const FIXTURE_ENTRYPOINT = {
24
+ fn: Component,
25
+ params: [{propValue: 'test'}],
26
+};
27
+
28
+```
29
+
30
+## Code
31
+
32
+```javascript
33
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
34
+import { useEffect, useState } from "react";
35
+
36
+function Component(t0) {
37
+ const $ = _c(6);
38
+ const { propValue } = t0;
39
+ const [value, setValue] = useState(null);
40
+ let t1;
41
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t1 = function localFunction() {
43
+ console.log("local function");
44
+ };
45
+ $[0] = t1;
46
+ } else {
47
+ t1 = $[0];
48
+ }
49
+ const localFunction = t1;
50
+ let t2;
51
+ let t3;
52
+ if ($[1] !== propValue) {
53
+ t2 = () => {
54
+ setValue(propValue);
55
+ localFunction();
56
+ };
57
+ t3 = [propValue];
58
+ $[1] = propValue;
59
+ $[2] = t2;
60
+ $[3] = t3;
61
+ } else {
62
+ t2 = $[2];
63
+ t3 = $[3];
64
+ }
65
+ useEffect(t2, t3);
66
+ let t4;
67
+ if ($[4] !== value) {
68
+ t4 = <div>{value}</div>;
69
+ $[4] = value;
70
+ $[5] = t4;
71
+ } else {
72
+ t4 = $[5];
73
+ }
74
+ return t4;
75
+}
76
+
77
+export const FIXTURE_ENTRYPOINT = {
78
+ fn: Component,
79
+ params: [{ propValue: "test" }],
80
+};
81
+
82
+```
83
+
84
+## Logs
85
+
86
+```
87
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [propValue]\n\nData Flow Tree:\n└── propValue (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":12,"column":4,"index":279},"end":{"line":12,"column":12,"index":287},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
88
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":17,"column":1,"index":371},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
89
+```
90
+
91
+### Eval output
92
+(kind: ok) <div>test</div>
93
+logs: ['local function']
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({propValue}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.expect.md
+9
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState} from 'react';
7
8
function Component({propValue, onChange}) {
@@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {
25
## Code
26
27
```javascript
28
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
28
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29
import { useEffect, useState } from "react";
30
31
function Component(t0) {
@@ -70,6 +70,13 @@ export const FIXTURE_ENTRYPOINT = {
70
};
71
72
```
73
+
74
+## Logs
75
+
76
+```
77
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":306},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
78
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":402},"end":{"line":16,"column":49,"index":410},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
79
+```
80
81
### Eval output
82
(kind: ok) <div>test</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({propValue, onChange}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md
+8
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState} from 'react';
7
8
function Component({propValue}) {
@@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {
25
## Code
26
27
```javascript
28
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
28
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29
import { useEffect, useState } from "react";
30
31
function Component(t0) {
@@ -65,6 +65,12 @@ export const FIXTURE_ENTRYPOINT = {
65
};
66
67
```
68
+
69
+## Logs
70
+
71
+```
72
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":12,"column":1,"index":298},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
73
+```
74
75
### Eval output
76
(kind: exception) globalCall is not defined
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component({propValue}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-conditionally-in-effect.expect.md
deleted
-58
@@ -1,58 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-function Component({value, enabled}) {
9
- const [localValue, setLocalValue] = useState('');
10
-
11
- useEffect(() => {
12
- if (enabled) {
13
- setLocalValue(value);
14
- } else {
15
- setLocalValue('disabled');
16
- }
17
- }, [value, enabled]);
18
-
19
- return <div>{localValue}</div>;
20
-}
21
-
22
-export const FIXTURE_ENTRYPOINT = {
23
- fn: Component,
24
- params: [{value: 'test', enabled: true}],
25
-};
26
-
27
-```
28
-
29
-
30
-## Error
31
-
32
-```
33
-Found 1 error:
34
-
35
-Error: You might not need an effect. Derive values in render, not effects.
36
-
37
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
38
-
39
-This setState call is setting a derived value that depends on the following reactive sources:
40
-
41
-Props: [value]
42
-
43
-Data Flow Tree:
44
-└── value (Prop)
45
-
46
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
47
-
48
-error.derived-state-conditionally-in-effect.ts:9:6
49
- 7 | useEffect(() => {
50
- 8 | if (enabled) {
51
-> 9 | setLocalValue(value);
52
- | ^^^^^^^^^^^^^ This should be computed during render, not in an effect
53
- 10 | } else {
54
- 11 | setLocalValue('disabled');
55
- 12 | }
56
-```
57
-
58
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-from-default-props.expect.md
deleted
-55
@@ -1,55 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-export default function Component({input = 'empty'}) {
9
- const [currInput, setCurrInput] = useState(input);
10
- const localConst = 'local const';
11
-
12
- useEffect(() => {
13
- setCurrInput(input + localConst);
14
- }, [input, localConst]);
15
-
16
- return <div>{currInput}</div>;
17
-}
18
-
19
-export const FIXTURE_ENTRYPOINT = {
20
- fn: Component,
21
- params: [{input: 'test'}],
22
-};
23
-
24
-```
25
-
26
-
27
-## Error
28
-
29
-```
30
-Found 1 error:
31
-
32
-Error: You might not need an effect. Derive values in render, not effects.
33
-
34
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
35
-
36
-This setState call is setting a derived value that depends on the following reactive sources:
37
-
38
-Props: [input]
39
-
40
-Data Flow Tree:
41
-└── input (Prop)
42
-
43
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
44
-
45
-error.derived-state-from-default-props.ts:9:4
46
- 7 |
47
- 8 | useEffect(() => {
48
-> 9 | setCurrInput(input + localConst);
49
- | ^^^^^^^^^^^^ This should be computed during render, not in an effect
50
- 10 | }, [input, localConst]);
51
- 11 |
52
- 12 | return <div>{currInput}</div>;
53
-```
54
-
55
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-from-local-state-in-effect.expect.md
deleted
-52
@@ -1,52 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-
7
-import {useEffect, useState} from 'react';
8
-
9
-function Component({shouldChange}) {
10
- const [count, setCount] = useState(0);
11
-
12
- useEffect(() => {
13
- if (shouldChange) {
14
- setCount(count + 1);
15
- }
16
- }, [count]);
17
-
18
- return <div>{count}</div>;
19
-}
20
-
21
-```
22
-
23
-
24
-## Error
25
-
26
-```
27
-Found 1 error:
28
-
29
-Error: You might not need an effect. Derive values in render, not effects.
30
-
31
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
32
-
33
-This setState call is setting a derived value that depends on the following reactive sources:
34
-
35
-State: [count]
36
-
37
-Data Flow Tree:
38
-└── count (State)
39
-
40
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
41
-
42
-error.derived-state-from-local-state-in-effect.ts:10:6
43
- 8 | useEffect(() => {
44
- 9 | if (shouldChange) {
45
-> 10 | setCount(count + 1);
46
- | ^^^^^^^^ This should be computed during render, not in an effect
47
- 11 | }
48
- 12 | }, [count]);
49
- 13 |
50
-```
51
-
52
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-from-prop-local-state-and-component-scope.expect.md
deleted
-64
@@ -1,64 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-function Component({firstName}) {
9
- const [lastName, setLastName] = useState('Doe');
10
- const [fullName, setFullName] = useState('John');
11
-
12
- const middleName = 'D.';
13
-
14
- useEffect(() => {
15
- setFullName(firstName + ' ' + middleName + ' ' + lastName);
16
- }, [firstName, middleName, lastName]);
17
-
18
- return (
19
- <div>
20
- <input value={lastName} onChange={e => setLastName(e.target.value)} />
21
- <div>{fullName}</div>
22
- </div>
23
- );
24
-}
25
-
26
-export const FIXTURE_ENTRYPOINT = {
27
- fn: Component,
28
- params: [{firstName: 'John'}],
29
-};
30
-
31
-```
32
-
33
-
34
-## Error
35
-
36
-```
37
-Found 1 error:
38
-
39
-Error: You might not need an effect. Derive values in render, not effects.
40
-
41
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
42
-
43
-This setState call is setting a derived value that depends on the following reactive sources:
44
-
45
-Props: [firstName]
46
-State: [lastName]
47
-
48
-Data Flow Tree:
49
-├── firstName (Prop)
50
-└── lastName (State)
51
-
52
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
53
-
54
-error.derived-state-from-prop-local-state-and-component-scope.ts:11:4
55
- 9 |
56
- 10 | useEffect(() => {
57
-> 11 | setFullName(firstName + ' ' + middleName + ' ' + lastName);
58
- | ^^^^^^^^^^^ This should be computed during render, not in an effect
59
- 12 | }, [firstName, middleName, lastName]);
60
- 13 |
61
- 14 | return (
62
-```
63
-
64
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-from-prop-setter-ternary.expect.md
deleted
-48
@@ -1,48 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-
7
-function Component({value}) {
8
- const [checked, setChecked] = useState('');
9
-
10
- useEffect(() => {
11
- setChecked(value === '' ? [] : value.split(','));
12
- }, [value]);
13
-
14
- return <div>{checked}</div>;
15
-}
16
-
17
-```
18
-
19
-
20
-## Error
21
-
22
-```
23
-Found 1 error:
24
-
25
-Error: You might not need an effect. Derive values in render, not effects.
26
-
27
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
28
-
29
-This setState call is setting a derived value that depends on the following reactive sources:
30
-
31
-Props: [value]
32
-
33
-Data Flow Tree:
34
-└── value (Prop)
35
-
36
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
37
-
38
-error.derived-state-from-prop-setter-ternary.ts:7:4
39
- 5 |
40
- 6 | useEffect(() => {
41
-> 7 | setChecked(value === '' ? [] : value.split(','));
42
- | ^^^^^^^^^^ This should be computed during render, not in an effect
43
- 8 | }, [value]);
44
- 9 |
45
- 10 | return <div>{checked}</div>;
46
-```
47
-
48
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.derived-state-from-prop-with-side-effect.expect.md
deleted
-55
@@ -1,55 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-function Component({value}) {
9
- const [localValue, setLocalValue] = useState('');
10
-
11
- useEffect(() => {
12
- setLocalValue(value);
13
- document.title = `Value: ${value}`;
14
- }, [value]);
15
-
16
- return <div>{localValue}</div>;
17
-}
18
-
19
-export const FIXTURE_ENTRYPOINT = {
20
- fn: Component,
21
- params: [{value: 'test'}],
22
-};
23
-
24
-```
25
-
26
-
27
-## Error
28
-
29
-```
30
-Found 1 error:
31
-
32
-Error: You might not need an effect. Derive values in render, not effects.
33
-
34
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
35
-
36
-This setState call is setting a derived value that depends on the following reactive sources:
37
-
38
-Props: [value]
39
-
40
-Data Flow Tree:
41
-└── value (Prop)
42
-
43
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
44
-
45
-error.derived-state-from-prop-with-side-effect.ts:8:4
46
- 6 |
47
- 7 | useEffect(() => {
48
-> 8 | setLocalValue(value);
49
- | ^^^^^^^^^^^^^ This should be computed during render, not in an effect
50
- 9 | document.title = `Value: ${value}`;
51
- 10 | }, [value]);
52
- 11 |
53
-```
54
-
55
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.effect-contains-local-function-call.expect.md
deleted
-59
@@ -1,59 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-function Component({propValue}) {
9
- const [value, setValue] = useState(null);
10
-
11
- function localFunction() {
12
- console.log('local function');
13
- }
14
-
15
- useEffect(() => {
16
- setValue(propValue);
17
- localFunction();
18
- }, [propValue]);
19
-
20
- return <div>{value}</div>;
21
-}
22
-
23
-export const FIXTURE_ENTRYPOINT = {
24
- fn: Component,
25
- params: [{propValue: 'test'}],
26
-};
27
-
28
-```
29
-
30
-
31
-## Error
32
-
33
-```
34
-Found 1 error:
35
-
36
-Error: You might not need an effect. Derive values in render, not effects.
37
-
38
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
39
-
40
-This setState call is setting a derived value that depends on the following reactive sources:
41
-
42
-Props: [propValue]
43
-
44
-Data Flow Tree:
45
-└── propValue (Prop)
46
-
47
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
48
-
49
-error.effect-contains-local-function-call.ts:12:4
50
- 10 |
51
- 11 | useEffect(() => {
52
-> 12 | setValue(propValue);
53
- | ^^^^^^^^ This should be computed during render, not in an effect
54
- 13 | localFunction();
55
- 14 | }, [propValue]);
56
- 15 |
57
-```
58
-
59
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.invalid-derived-computation-in-effect.expect.md
deleted
-57
@@ -1,57 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-function Component() {
9
- const [firstName, setFirstName] = useState('Taylor');
10
- const lastName = 'Swift';
11
-
12
- // 🔴 Avoid: redundant state and unnecessary Effect
13
- const [fullName, setFullName] = useState('');
14
- useEffect(() => {
15
- setFullName(firstName + ' ' + lastName);
16
- }, [firstName, lastName]);
17
-
18
- return <div>{fullName}</div>;
19
-}
20
-
21
-export const FIXTURE_ENTRYPOINT = {
22
- fn: Component,
23
- params: [],
24
-};
25
-
26
-```
27
-
28
-
29
-## Error
30
-
31
-```
32
-Found 1 error:
33
-
34
-Error: You might not need an effect. Derive values in render, not effects.
35
-
36
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
37
-
38
-This setState call is setting a derived value that depends on the following reactive sources:
39
-
40
-State: [firstName]
41
-
42
-Data Flow Tree:
43
-└── firstName (State)
44
-
45
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
46
-
47
-error.invalid-derived-computation-in-effect.ts:11:4
48
- 9 | const [fullName, setFullName] = useState('');
49
- 10 | useEffect(() => {
50
-> 11 | setFullName(firstName + ' ' + lastName);
51
- | ^^^^^^^^^^^ This should be computed during render, not in an effect
52
- 12 | }, [firstName, lastName]);
53
- 13 |
54
- 14 | return <div>{fullName}</div>;
55
-```
56
-
57
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.invalid-derived-state-from-computed-props.expect.md
deleted
-56
@@ -1,56 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-export default function Component(props) {
9
- const [displayValue, setDisplayValue] = useState('');
10
-
11
- useEffect(() => {
12
- const computed = props.prefix + props.value + props.suffix;
13
- setDisplayValue(computed);
14
- }, [props.prefix, props.value, props.suffix]);
15
-
16
- return <div>{displayValue}</div>;
17
-}
18
-
19
-export const FIXTURE_ENTRYPOINT = {
20
- fn: Component,
21
- params: [{prefix: '[', value: 'test', suffix: ']'}],
22
-};
23
-
24
-```
25
-
26
-
27
-## Error
28
-
29
-```
30
-Found 1 error:
31
-
32
-Error: You might not need an effect. Derive values in render, not effects.
33
-
34
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
35
-
36
-This setState call is setting a derived value that depends on the following reactive sources:
37
-
38
-Props: [props]
39
-
40
-Data Flow Tree:
41
-└── computed
42
- └── props (Prop)
43
-
44
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
45
-
46
-error.invalid-derived-state-from-computed-props.ts:9:4
47
- 7 | useEffect(() => {
48
- 8 | const computed = props.prefix + props.value + props.suffix;
49
-> 9 | setDisplayValue(computed);
50
- | ^^^^^^^^^^^^^^^ This should be computed during render, not in an effect
51
- 10 | }, [props.prefix, props.value, props.suffix]);
52
- 11 |
53
- 12 | return <div>{displayValue}</div>;
54
-```
55
-
56
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.invalid-derived-state-from-destructured-props.expect.md
deleted
-56
@@ -1,56 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
6
-import {useEffect, useState} from 'react';
7
-
8
-export default function Component({props}) {
9
- const [fullName, setFullName] = useState(
10
- props.firstName + ' ' + props.lastName
11
- );
12
-
13
- useEffect(() => {
14
- setFullName(props.firstName + ' ' + props.lastName);
15
- }, [props.firstName, props.lastName]);
16
-
17
- return <div>{fullName}</div>;
18
-}
19
-
20
-export const FIXTURE_ENTRYPOINT = {
21
- fn: Component,
22
- params: [{props: {firstName: 'John', lastName: 'Doe'}}],
23
-};
24
-
25
-```
26
-
27
-
28
-## Error
29
-
30
-```
31
-Found 1 error:
32
-
33
-Error: You might not need an effect. Derive values in render, not effects.
34
-
35
-Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user
36
-
37
-This setState call is setting a derived value that depends on the following reactive sources:
38
-
39
-Props: [props]
40
-
41
-Data Flow Tree:
42
-└── props (Prop)
43
-
44
-See: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state.
45
-
46
-error.invalid-derived-state-from-destructured-props.ts:10:4
47
- 8 |
48
- 9 | useEffect(() => {
49
-> 10 | setFullName(props.firstName + ' ' + props.lastName);
50
- | ^^^^^^^^^^^ This should be computed during render, not in an effect
51
- 11 | }, [props.firstName, props.lastName]);
52
- 12 |
53
- 13 | return <div>{fullName}</div>;
54
-```
55
-
56
-
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md
new
+80
@@ -0,0 +1,80 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+function Component() {
9
+ const [firstName, setFirstName] = useState('Taylor');
10
+ const lastName = 'Swift';
11
+
12
+ // 🔴 Avoid: redundant state and unnecessary Effect
13
+ const [fullName, setFullName] = useState('');
14
+ useEffect(() => {
15
+ setFullName(firstName + ' ' + lastName);
16
+ }, [firstName, lastName]);
17
+
18
+ return <div>{fullName}</div>;
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Component,
23
+ params: [],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
32
+import { useEffect, useState } from "react";
33
+
34
+function Component() {
35
+ const $ = _c(5);
36
+ const [firstName] = useState("Taylor");
37
+
38
+ const [fullName, setFullName] = useState("");
39
+ let t0;
40
+ let t1;
41
+ if ($[0] !== firstName) {
42
+ t0 = () => {
43
+ setFullName(firstName + " " + "Swift");
44
+ };
45
+ t1 = [firstName, "Swift"];
46
+ $[0] = firstName;
47
+ $[1] = t0;
48
+ $[2] = t1;
49
+ } else {
50
+ t0 = $[1];
51
+ t1 = $[2];
52
+ }
53
+ useEffect(t0, t1);
54
+ let t2;
55
+ if ($[3] !== fullName) {
56
+ t2 = <div>{fullName}</div>;
57
+ $[3] = fullName;
58
+ $[4] = t2;
59
+ } else {
60
+ t2 = $[4];
61
+ }
62
+ return t2;
63
+}
64
+
65
+export const FIXTURE_ENTRYPOINT = {
66
+ fn: Component,
67
+ params: [],
68
+};
69
+
70
+```
71
+
72
+## Logs
73
+
74
+```
75
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nState: [firstName]\n\nData Flow Tree:\n└── firstName (State)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":11,"column":4,"index":341},"end":{"line":11,"column":15,"index":352},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
76
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":107},"end":{"line":15,"column":1,"index":445},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
77
+```
78
+
79
+### Eval output
80
+(kind: ok) <div>Taylor Swift</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.expect.md
new
+79
@@ -0,0 +1,79 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+export default function Component(props) {
9
+ const [displayValue, setDisplayValue] = useState('');
10
+
11
+ useEffect(() => {
12
+ const computed = props.prefix + props.value + props.suffix;
13
+ setDisplayValue(computed);
14
+ }, [props.prefix, props.value, props.suffix]);
15
+
16
+ return <div>{displayValue}</div>;
17
+}
18
+
19
+export const FIXTURE_ENTRYPOINT = {
20
+ fn: Component,
21
+ params: [{prefix: '[', value: 'test', suffix: ']'}],
22
+};
23
+
24
+```
25
+
26
+## Code
27
+
28
+```javascript
29
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
30
+import { useEffect, useState } from "react";
31
+
32
+export default function Component(props) {
33
+ const $ = _c(7);
34
+ const [displayValue, setDisplayValue] = useState("");
35
+ let t0;
36
+ let t1;
37
+ if ($[0] !== props.prefix || $[1] !== props.suffix || $[2] !== props.value) {
38
+ t0 = () => {
39
+ const computed = props.prefix + props.value + props.suffix;
40
+ setDisplayValue(computed);
41
+ };
42
+ t1 = [props.prefix, props.value, props.suffix];
43
+ $[0] = props.prefix;
44
+ $[1] = props.suffix;
45
+ $[2] = props.value;
46
+ $[3] = t0;
47
+ $[4] = t1;
48
+ } else {
49
+ t0 = $[3];
50
+ t1 = $[4];
51
+ }
52
+ useEffect(t0, t1);
53
+ let t2;
54
+ if ($[5] !== displayValue) {
55
+ t2 = <div>{displayValue}</div>;
56
+ $[5] = displayValue;
57
+ $[6] = t2;
58
+ } else {
59
+ t2 = $[6];
60
+ }
61
+ return t2;
62
+}
63
+
64
+export const FIXTURE_ENTRYPOINT = {
65
+ fn: Component,
66
+ params: [{ prefix: "[", value: "test", suffix: "]" }],
67
+};
68
+
69
+```
70
+
71
+## Logs
72
+
73
+```
74
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── computed\n └── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":9,"column":4,"index":295},"end":{"line":9,"column":19,"index":310},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
75
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":13,"column":1,"index":409},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
76
+```
77
+
78
+### Eval output
79
+(kind: ok) <div>[test]</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
export default function Component(props) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.expect.md
new
+81
@@ -0,0 +1,81 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
+import {useEffect, useState} from 'react';
7
+
8
+export default function Component({props}) {
9
+ const [fullName, setFullName] = useState(
10
+ props.firstName + ' ' + props.lastName
11
+ );
12
+
13
+ useEffect(() => {
14
+ setFullName(props.firstName + ' ' + props.lastName);
15
+ }, [props.firstName, props.lastName]);
16
+
17
+ return <div>{fullName}</div>;
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Component,
22
+ params: [{props: {firstName: 'John', lastName: 'Doe'}}],
23
+};
24
+
25
+```
26
+
27
+## Code
28
+
29
+```javascript
30
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
31
+import { useEffect, useState } from "react";
32
+
33
+export default function Component(t0) {
34
+ const $ = _c(6);
35
+ const { props } = t0;
36
+ const [fullName, setFullName] = useState(
37
+ props.firstName + " " + props.lastName,
38
+ );
39
+ let t1;
40
+ let t2;
41
+ if ($[0] !== props.firstName || $[1] !== props.lastName) {
42
+ t1 = () => {
43
+ setFullName(props.firstName + " " + props.lastName);
44
+ };
45
+ t2 = [props.firstName, props.lastName];
46
+ $[0] = props.firstName;
47
+ $[1] = props.lastName;
48
+ $[2] = t1;
49
+ $[3] = t2;
50
+ } else {
51
+ t1 = $[2];
52
+ t2 = $[3];
53
+ }
54
+ useEffect(t1, t2);
55
+ let t3;
56
+ if ($[4] !== fullName) {
57
+ t3 = <div>{fullName}</div>;
58
+ $[4] = fullName;
59
+ $[5] = t3;
60
+ } else {
61
+ t3 = $[5];
62
+ }
63
+ return t3;
64
+}
65
+
66
+export const FIXTURE_ENTRYPOINT = {
67
+ fn: Component,
68
+ params: [{ props: { firstName: "John", lastName: "Doe" } }],
69
+};
70
+
71
+```
72
+
73
+## Logs
74
+
75
+```
76
+{"kind":"CompileError","detail":{"options":{"description":"Using an effect triggers an additional render which can hurt performance and user experience, potentially briefly showing stale values to the user\n\nThis setState call is setting a derived value that depends on the following reactive sources:\n\nProps: [props]\n\nData Flow Tree:\n└── props (Prop)\n\nSee: https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state","category":"EffectDerivationsOfState","reason":"You might not need an effect. Derive values in render, not effects.","details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":269},"end":{"line":10,"column":15,"index":280},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
77
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":122},"end":{"line":14,"column":1,"index":397},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
78
+```
79
+
80
+### Eval output
81
+(kind: ok) <div>John Doe</div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState} from 'react';
3
4
export default function Component({props}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.expect.md
+8
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @validateNoDerivedComputationsInEffects_exp
5
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
6
import {useEffect, useState, useRef} from 'react';
7
8
export default function Component({test}) {
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
31
## Code
32
33
```javascript
34
-import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
34
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
35
import { useEffect, useState, useRef } from "react";
36
37
export default function Component(t0) {
@@ -77,6 +77,12 @@ export const FIXTURE_ENTRYPOINT = {
77
};
78
79
```
80
+
81
+## Logs
82
+
83
+```
84
+{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":130},"end":{"line":18,"column":1,"index":386},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
85
+```
86
87
### Eval output
88
(kind: ok) 8
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @validateNoDerivedComputationsInEffects_exp
1
+// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
2
import {useEffect, useState, useRef} from 'react';
3
4
export default function Component({test}) {