@samitouri / QOS-React / commits / 38a6f4e4a1

[compiler] Only run validations with env.logErrors on outputMode: 'lint' (#35216)

Summary: These validations are not essential for compilation, with this we only run that logic when outputMode is 'lint' Test Plan: Update fixtures and run tests

Jorge Cabiedes committed Dec 11, 2025 at 16:36 UTC 38a6f4e4a11f128a2f83047c5e64512f7678d450
83 files changed +490 -1188
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+11 -4
@@ -279,17 +279,20 @@ function runWithEnvironment(
279 validateNoSetStateInRender(hir).unwrap();
280 }
281
282 - if (env.config.validateNoDerivedComputationsInEffects_exp) {
282 + if (
283 + env.config.validateNoDerivedComputationsInEffects_exp &&
284 + env.outputMode === 'lint'
285 + ) {
286 env.logErrors(validateNoDerivedComputationsInEffects_exp(hir));
287 } else if (env.config.validateNoDerivedComputationsInEffects) {
288 validateNoDerivedComputationsInEffects(hir);
289 }
290
288 - if (env.config.validateNoSetStateInEffects) {
291 + if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') {
292 env.logErrors(validateNoSetStateInEffects(hir, env));
293 }
294
292 - if (env.config.validateNoJSXInTryStatements) {
295 + if (env.config.validateNoJSXInTryStatements && env.outputMode === 'lint') {
296 env.logErrors(validateNoJSXInTryStatement(hir));
297 }
298
@@ -320,7 +323,11 @@ function runWithEnvironment(
323 value: hir,
324 });
325
323 - if (env.enableValidations && env.config.validateStaticComponents) {
326 + if (
327 + env.enableValidations &&
328 + env.config.validateStaticComponents &&
329 + env.outputMode === 'lint'
330 + ) {
331 env.logErrors(validateStaticComponents(hir));
332 }
333
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md
+15 -36
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({value, enabled}) {
@@ -29,42 +29,21 @@ export const FIXTURE_ENTRYPOINT = {
29 ## Code
30
31 ```javascript
32 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
32 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
33 import { useEffect, useState } from "react";
34
35 -function Component(t0) {
36 - const $ = _c(6);
37 - const { value, enabled } = t0;
35 +function Component({ value, enabled }) {
36 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 - t2 = [value, enabled];
50 - $[0] = enabled;
51 - $[1] = value;
52 - $[2] = t1;
53 - $[3] = t2;
54 - } else {
55 - t1 = $[2];
56 - t2 = $[3];
57 - }
58 - useEffect(t1, t2);
59 - let t3;
60 - if ($[4] !== localValue) {
61 - t3 = <div>{localValue}</div>;
62 - $[4] = localValue;
63 - $[5] = t3;
64 - } else {
65 - t3 = $[5];
66 - }
67 - return t3;
37 +
38 + useEffect(() => {
39 + if (enabled) {
40 + setLocalValue(value);
41 + } else {
42 + setLocalValue("disabled");
43 + }
44 + }, [value, enabled]);
45 +
46 + return <div>{localValue}</div>;
47 }
48
49 export const FIXTURE_ENTRYPOINT = {
@@ -77,8 +56,8 @@ export const FIXTURE_ENTRYPOINT = {
56 ## Logs
57
58 ```
80 -{"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}
81 -{"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}
59 +{"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":263},"end":{"line":9,"column":19,"index":276},"filename":"derived-state-conditionally-in-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
60 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":397},"filename":"derived-state-conditionally-in-effect.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
61 ```
62
63 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+12 -32
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 export default function Component({input = 'empty'}) {
@@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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;
32 +export default function Component({ input = "empty" }) {
33 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;
34 + const localConst = "local const";
35 +
36 + useEffect(() => {
37 + setCurrInput(input + localConst);
38 + }, [input, localConst]);
39 +
40 + return <div>{currInput}</div>;
41 }
42
43 export const FIXTURE_ENTRYPOINT = {
@@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
50 ## Logs
51
52 ```
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}
53 +{"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":295},"end":{"line":9,"column":16,"index":307},"filename":"derived-state-from-default-props.ts","identifierName":"setCurrInput"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
54 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":391},"filename":"derived-state-from-default-props.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
55 ```
56
57 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+13 -38
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6
7 import {useEffect, useState} from 'react';
8
@@ -23,45 +23,20 @@ function Component({shouldChange}) {
23 ## Code
24
25 ```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
26 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
27
28 import { useEffect, useState } from "react";
29
30 -function Component(t0) {
31 - const $ = _c(7);
32 - const { shouldChange } = t0;
30 +function Component({ shouldChange }) {
31 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;
32 +
33 + useEffect(() => {
34 + if (shouldChange) {
35 + setCount(count + 1);
36 + }
37 + }, [count]);
38 +
39 + return <div>{count}</div>;
40 }
41
42 ```
@@ -69,8 +44,8 @@ function Component(t0) {
44 ## Logs
45
46 ```
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}
47 +{"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":256},"end":{"line":10,"column":14,"index":264},"filename":"derived-state-from-local-state-in-effect.ts","identifierName":"setCount"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
48 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":15,"column":1,"index":329},"filename":"derived-state-from-local-state-in-effect.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
49 ```
50
51 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+18 -61
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({firstName}) {
@@ -33,68 +33,25 @@ export const FIXTURE_ENTRYPOINT = {
33 ## Code
34
35 ```javascript
36 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
36 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
37 import { useEffect, useState } from "react";
38
39 -function Component(t0) {
40 - const $ = _c(12);
41 - const { firstName } = t0;
39 +function Component({ firstName }) {
40 const [lastName, setLastName] = useState("Doe");
41 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;
42 +
43 + const middleName = "D.";
44 +
45 + useEffect(() => {
46 + setFullName(firstName + " " + middleName + " " + lastName);
47 + }, [firstName, middleName, lastName]);
48 +
49 + return (
50 + <div>
51 + <input value={lastName} onChange={(e) => setLastName(e.target.value)} />
52 + <div>{fullName}</div>
53 + </div>
54 + );
55 }
56
57 export const FIXTURE_ENTRYPOINT = {
@@ -107,8 +64,8 @@ export const FIXTURE_ENTRYPOINT = {
64 ## Logs
65
66 ```
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}
67 +{"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":316},"end":{"line":11,"column":15,"index":327},"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}
68 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":20,"column":1,"index":561},"filename":"derived-state-from-prop-local-state-and-component-scope.ts"},"fnName":"Component","memoSlots":12,"memoBlocks":5,"memoValues":6,"prunedMemoBlocks":0,"prunedMemoValues":0}
69 ```
70
71 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+14 -41
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({initialName}) {
@@ -29,48 +29,21 @@ export const FIXTURE_ENTRYPOINT = {
29 ## Code
30
31 ```javascript
32 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
32 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
33 import { useEffect, useState } from "react";
34
35 -function Component(t0) {
36 - const $ = _c(6);
37 - const { initialName } = t0;
35 +function Component({ initialName }) {
36 const [name, setName] = useState("");
39 - let t1;
40 - let t2;
41 - if ($[0] !== initialName) {
42 - t1 = () => {
43 - setName(initialName);
44 - };
45 - t2 = [initialName];
46 - $[0] = initialName;
47 - $[1] = t1;
48 - $[2] = t2;
49 - } else {
50 - t1 = $[1];
51 - t2 = $[2];
52 - }
53 - useEffect(t1, t2);
54 - let t3;
55 - if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
56 - t3 = (e) => setName(e.target.value);
57 - $[3] = t3;
58 - } else {
59 - t3 = $[3];
60 - }
61 - let t4;
62 - if ($[4] !== name) {
63 - t4 = (
64 - <div>
65 - <input value={name} onChange={t3} />
66 - </div>
67 - );
68 - $[4] = name;
69 - $[5] = t4;
70 - } else {
71 - t4 = $[5];
72 - }
73 - return t4;
37 +
38 + useEffect(() => {
39 + setName(initialName);
40 + }, [initialName]);
41 +
42 + return (
43 + <div>
44 + <input value={name} onChange={(e) => setName(e.target.value)} />
45 + </div>
46 + );
47 }
48
49 export const FIXTURE_ENTRYPOINT = {
@@ -83,7 +56,7 @@ export const FIXTURE_ENTRYPOINT = {
56 ## Logs
57
58 ```
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}
59 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":16,"column":1,"index":378},"filename":"derived-state-from-prop-setter-call-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
60 ```
61
62 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+9 -29
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp
5 +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
6
7 function Component({value}) {
8 const [checked, setChecked] = useState('');
@@ -19,36 +19,16 @@ function Component({value}) {
19 ## Code
20
21 ```javascript
22 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
22 +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
23
24 -function Component(t0) {
25 - const $ = _c(5);
26 - const { value } = t0;
24 +function Component({ value }) {
25 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;
26 +
27 + useEffect(() => {
28 + setChecked(value === "" ? [] : value.split(","));
29 + }, [value]);
30 +
31 + return <div>{checked}</div>;
32 }
33
34 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp
1 +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint"
2
3 function Component({value}) {
4 const [checked, setChecked] = useState('');
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
+13 -43
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function MockComponent({onSet}) {
@@ -28,50 +28,20 @@ export const FIXTURE_ENTRYPOINT = {
28 ## Code
29
30 ```javascript
31 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
31 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
32 import { useEffect, useState } from "react";
33
34 -function MockComponent(t0) {
35 - const $ = _c(2);
36 - const { onSet } = t0;
37 - let t1;
38 - if ($[0] !== onSet) {
39 - t1 = <div onClick={() => onSet("clicked")}>Mock Component</div>;
40 - $[0] = onSet;
41 - $[1] = t1;
42 - } else {
43 - t1 = $[1];
44 - }
45 - return t1;
34 +function MockComponent({ onSet }) {
35 + return <div onClick={() => onSet("clicked")}>Mock Component</div>;
36 }
37
48 -function Component(t0) {
49 - const $ = _c(4);
50 - const { propValue } = t0;
51 - const [, setValue] = useState(null);
52 - let t1;
53 - let t2;
54 - if ($[0] !== propValue) {
55 - t1 = () => {
56 - setValue(propValue);
57 - };
58 - t2 = [propValue];
59 - $[0] = propValue;
60 - $[1] = t1;
61 - $[2] = t2;
62 - } else {
63 - t1 = $[1];
64 - t2 = $[2];
65 - }
66 - useEffect(t1, t2);
67 - let t3;
68 - if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
69 - t3 = <MockComponent onSet={setValue} />;
70 - $[3] = t3;
71 - } else {
72 - t3 = $[3];
73 - }
74 - return t3;
38 +function Component({ propValue }) {
39 + const [value, setValue] = useState(null);
40 + useEffect(() => {
41 + setValue(propValue);
42 + }, [propValue]);
43 +
44 + return <MockComponent onSet={setValue} />;
45 }
46
47 export const FIXTURE_ENTRYPOINT = {
@@ -84,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = {
54 ## Logs
55
56 ```
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}
57 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":6,"column":1,"index":230},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"MockComponent","memoSlots":2,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
58 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":8,"column":0,"index":232},"end":{"line":15,"column":1,"index":421},"filename":"derived-state-from-prop-setter-used-outside-effect-no-error.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
59 ```
60
61 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+12 -32
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({value}) {
@@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
30 import { useEffect, useState } from "react";
31
32 -function Component(t0) {
33 - const $ = _c(5);
34 - const { value } = t0;
32 +function Component({ value }) {
33 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;
34 +
35 + useEffect(() => {
36 + setLocalValue(value);
37 + document.title = `Value: ${value}`;
38 + }, [value]);
39 +
40 + return <div>{localValue}</div>;
41 }
42
43 export const FIXTURE_ENTRYPOINT = {
@@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
50 ## Logs
51
52 ```
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}
53 +{"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":233},"end":{"line":8,"column":17,"index":246},"filename":"derived-state-from-prop-with-side-effect.ts","identifierName":"setLocalValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
54 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":13,"column":1,"index":346},"filename":"derived-state-from-prop-with-side-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
55 ```
56
57 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+10 -30
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState, useRef} from 'react';
7
8 export default function Component({test}) {
@@ -27,39 +27,19 @@ export const FIXTURE_ENTRYPOINT = {
27 ## Code
28
29 ```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
30 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
31 import { useEffect, useState, useRef } from "react";
32
33 -export default function Component(t0) {
34 - const $ = _c(5);
35 - const { test } = t0;
33 +export default function Component({ test }) {
34 const [local, setLocal] = useState("");
35
36 const myRef = useRef(null);
39 - let t1;
40 - let t2;
41 - if ($[0] !== test) {
42 - t1 = () => {
43 - setLocal(myRef.current + test);
44 - };
45 - t2 = [test];
46 - $[0] = test;
47 - $[1] = t1;
48 - $[2] = t2;
49 - } else {
50 - t1 = $[1];
51 - t2 = $[2];
52 - }
53 - useEffect(t1, t2);
54 - let t3;
55 - if ($[3] !== local) {
56 - t3 = <>{local}</>;
57 - $[3] = local;
58 - $[4] = t3;
59 - } else {
60 - t3 = $[4];
61 - }
62 - return t3;
37 +
38 + useEffect(() => {
39 + setLocal(myRef.current + test);
40 + }, [test]);
41 +
42 + return <>{local}</>;
43 }
44
45 export const FIXTURE_ENTRYPOINT = {
@@ -72,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = {
52 ## Logs
53
54 ```
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}
55 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":14,"column":1,"index":347},"filename":"derived-state-from-ref-and-state-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
56 ```
57
58 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+15 -41
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({propValue}) {
@@ -30,48 +30,22 @@ export const FIXTURE_ENTRYPOINT = {
30 ## Code
31
32 ```javascript
33 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
33 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
34 import { useEffect, useState } from "react";
35
36 -function Component(t0) {
37 - const $ = _c(6);
38 - const { propValue } = t0;
36 +function Component({ propValue }) {
37 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];
38 +
39 + function localFunction() {
40 + console.log("local function");
41 }
74 - return t4;
42 +
43 + useEffect(() => {
44 + setValue(propValue);
45 + localFunction();
46 + }, [propValue]);
47 +
48 + return <div>{value}</div>;
49 }
50
51 export const FIXTURE_ENTRYPOINT = {
@@ -84,8 +58,8 @@ export const FIXTURE_ENTRYPOINT = {
58 ## Logs
59
60 ```
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}
61 +{"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":298},"end":{"line":12,"column":12,"index":306},"filename":"effect-contains-local-function-call.ts","identifierName":"setValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
62 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":17,"column":1,"index":390},"filename":"effect-contains-local-function-call.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":3,"memoValues":4,"prunedMemoBlocks":0,"prunedMemoValues":0}
63 ```
64
65 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+11 -37
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({propValue, onChange}) {
@@ -25,43 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
25 ## Code
26
27 ```javascript
28 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
28 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
29 import { useEffect, useState } from "react";
30
31 -function Component(t0) {
32 - const $ = _c(7);
33 - const { propValue, onChange } = t0;
31 +function Component({ propValue, onChange }) {
32 const [value, setValue] = useState(null);
35 - let t1;
36 - if ($[0] !== onChange || $[1] !== propValue) {
37 - t1 = () => {
38 - setValue(propValue);
39 - onChange();
40 - };
41 - $[0] = onChange;
42 - $[1] = propValue;
43 - $[2] = t1;
44 - } else {
45 - t1 = $[2];
46 - }
47 - let t2;
48 - if ($[3] !== propValue) {
49 - t2 = [propValue];
50 - $[3] = propValue;
51 - $[4] = t2;
52 - } else {
53 - t2 = $[4];
54 - }
55 - useEffect(t1, t2);
56 - let t3;
57 - if ($[5] !== value) {
58 - t3 = <div>{value}</div>;
59 - $[5] = value;
60 - $[6] = t3;
61 - } else {
62 - t3 = $[6];
63 - }
64 - return t3;
33 + useEffect(() => {
34 + setValue(propValue);
35 + onChange();
36 + }, [propValue]);
37 +
38 + return <div>{value}</div>;
39 }
40
41 export const FIXTURE_ENTRYPOINT = {
@@ -74,8 +48,8 @@ export const FIXTURE_ENTRYPOINT = {
48 ## Logs
49
50 ```
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}
51 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":325},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
52 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":16,"column":41,"index":421},"end":{"line":16,"column":49,"index":429},"filename":"effect-contains-prop-function-call-no-error.ts"},"fnName":null,"memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
54
55 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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-used-in-dep-array-still-errors.expect.md
+12 -33
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6
7 function Component({prop}) {
8 const [s, setS] = useState(0);
@@ -18,36 +18,15 @@ function Component({prop}) {
18 ## Code
19
20 ```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
22 -
23 -function Component(t0) {
24 - const $ = _c(5);
25 - const { prop } = t0;
26 - const [, setS] = useState(0);
27 - let t1;
28 - let t2;
29 - if ($[0] !== prop) {
30 - t1 = () => {
31 - setS(prop);
32 - };
33 - t2 = [prop, setS];
34 - $[0] = prop;
35 - $[1] = t1;
36 - $[2] = t2;
37 - } else {
38 - t1 = $[1];
39 - t2 = $[2];
40 - }
41 - useEffect(t1, t2);
42 - let t3;
43 - if ($[3] !== prop) {
44 - t3 = <div>{prop}</div>;
45 - $[3] = prop;
46 - $[4] = t3;
47 - } else {
48 - t3 = $[4];
49 - }
50 - return t3;
21 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
22 +
23 +function Component({ prop }) {
24 + const [s, setS] = useState(0);
25 + useEffect(() => {
26 + setS(prop);
27 + }, [prop, setS]);
28 +
29 + return <div>{prop}</div>;
30 }
31
32 ```
@@ -55,8 +34,8 @@ function Component(t0) {
34 ## Logs
35
36 ```
58 -{"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: [prop]\n\nData Flow Tree:\n└── prop (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":6,"column":4,"index":150},"end":{"line":6,"column":8,"index":154},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
59 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":10,"column":1,"index":212},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
37 +{"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: [prop]\n\nData Flow Tree:\n└── prop (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":6,"column":4,"index":169},"end":{"line":6,"column":8,"index":173},"filename":"effect-used-in-dep-array-still-errors.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
38 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":10,"column":1,"index":231},"filename":"effect-used-in-dep-array-still-errors.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
39 ```
40
41 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
2
3 function Component({prop}) {
4 const [s, setS] = useState(0);
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.expect.md
+18 -31
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6
7 import {useEffect, useState} from 'react';
8
@@ -29,39 +29,26 @@ function Component(file: File) {
29 ## Code
30
31 ```javascript
32 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
32 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
33
34 import { useEffect, useState } from "react";
35
36 -function Component(file) {
37 - const $ = _c(5);
36 +function Component(file: File) {
37 const [imageUrl, setImageUrl] = useState(null);
39 - let t0;
40 - let t1;
41 - if ($[0] !== file) {
42 - t0 = () => {
43 - const imageUrlPrepared = URL.createObjectURL(file);
44 - setImageUrl(imageUrlPrepared);
45 - return () => URL.revokeObjectURL(imageUrlPrepared);
46 - };
47 - t1 = [file];
48 - $[0] = file;
49 - $[1] = t0;
50 - $[2] = t1;
51 - } else {
52 - t0 = $[1];
53 - t1 = $[2];
54 - }
55 - useEffect(t0, t1);
56 - let t2;
57 - if ($[3] !== imageUrl) {
58 - t2 = <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
59 - $[3] = imageUrl;
60 - $[4] = t2;
61 - } else {
62 - t2 = $[4];
63 - }
64 - return t2;
38 +
39 + /*
40 + * Cleaning up the variable or a source of the variable used to setState
41 + * inside the effect communicates that we always need to clean up something
42 + * which is a valid use case for useEffect. In which case we want to
43 + * avoid an throwing
44 + */
45 + useEffect(() => {
46 + const imageUrlPrepared = URL.createObjectURL(file);
47 + setImageUrl(imageUrlPrepared);
48 + return () => URL.revokeObjectURL(imageUrlPrepared);
49 + }, [file]);
50 +
51 + return <Image src={imageUrl} xstyle={styles.imageSizeLimits} />;
52 }
53
54 ```
@@ -69,7 +56,7 @@ function Component(file) {
56 ## Logs
57
58 ```
72 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":108},"end":{"line":21,"column":1,"index":700},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
59 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":127},"end":{"line":21,"column":1,"index":719},"filename":"effect-with-cleanup-function-depending-on-derived-computation-value.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
60 ```
61
62 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
2
3 import {useEffect, useState} from 'react';
4
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md
+10 -31
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component({propValue}) {
@@ -25,38 +25,17 @@ export const FIXTURE_ENTRYPOINT = {
25 ## Code
26
27 ```javascript
28 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
28 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
29 import { useEffect, useState } from "react";
30
31 -function Component(t0) {
32 - const $ = _c(5);
33 - const { propValue } = t0;
31 +function Component({ propValue }) {
32 const [value, setValue] = useState(null);
35 - let t1;
36 - let t2;
37 - if ($[0] !== propValue) {
38 - t1 = () => {
39 - setValue(propValue);
40 - globalCall();
41 - };
42 - t2 = [propValue];
43 - $[0] = propValue;
44 - $[1] = t1;
45 - $[2] = t2;
46 - } else {
47 - t1 = $[1];
48 - t2 = $[2];
49 - }
50 - useEffect(t1, t2);
51 - let t3;
52 - if ($[3] !== value) {
53 - t3 = <div>{value}</div>;
54 - $[3] = value;
55 - $[4] = t3;
56 - } else {
57 - t3 = $[4];
58 - }
59 - return t3;
33 + useEffect(() => {
34 + setValue(propValue);
35 + globalCall();
36 + }, [propValue]);
37 +
38 + return <div>{value}</div>;
39 }
40
41 export const FIXTURE_ENTRYPOINT = {
@@ -69,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = {
48 ## Logs
49
50 ```
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}
51 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":12,"column":1,"index":317},"filename":"effect-with-global-function-call-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
52 ```
53
54 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
2 import {useEffect, useState} from 'react';
3
4 function Component({propValue}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.expect.md
+9 -35
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
6
7 function Component({setParentState, prop}) {
8 useEffect(() => {
@@ -17,40 +17,14 @@ function Component({setParentState, prop}) {
17 ## Code
18
19 ```javascript
20 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
20 +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
21
22 -function Component(t0) {
23 - const $ = _c(7);
24 - const { setParentState, prop } = t0;
25 - let t1;
26 - if ($[0] !== prop || $[1] !== setParentState) {
27 - t1 = () => {
28 - setParentState(prop);
29 - };
30 - $[0] = prop;
31 - $[1] = setParentState;
32 - $[2] = t1;
33 - } else {
34 - t1 = $[2];
35 - }
36 - let t2;
37 - if ($[3] !== prop) {
38 - t2 = [prop];
39 - $[3] = prop;
40 - $[4] = t2;
41 - } else {
42 - t2 = $[4];
43 - }
44 - useEffect(t1, t2);
45 - let t3;
46 - if ($[5] !== prop) {
47 - t3 = <div>{prop}</div>;
48 - $[5] = prop;
49 - $[6] = t3;
50 - } else {
51 - t3 = $[6];
52 - }
53 - return t3;
22 +function Component({ setParentState, prop }) {
23 + useEffect(() => {
24 + setParentState(prop);
25 + }, [prop]);
26 +
27 + return <div>{prop}</div>;
28 }
29
30 ```
@@ -58,7 +32,7 @@ function Component(t0) {
32 ## Logs
33
34 ```
61 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":105},"end":{"line":9,"column":1,"index":240},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
35 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":124},"end":{"line":9,"column":1,"index":259},"filename":"from-props-setstate-in-effect-no-error.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
36 ```
37
38 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint"
2
3 function Component({setParentState, prop}) {
4 useEffect(() => {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.expect.md
+32 -58
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6
7 function Component() {
8 const [foo, setFoo] = useState({});
@@ -40,63 +40,37 @@ function Component() {
40 ## Code
41
42 ```javascript
43 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
43 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
44
45 function Component() {
46 - const $ = _c(9);
47 - let t0;
48 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
49 - t0 = {};
50 - $[0] = t0;
51 - } else {
52 - t0 = $[0];
53 - }
54 - const [foo, setFoo] = useState(t0);
55 - let t1;
56 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
57 - t1 = new Set();
58 - $[1] = t1;
59 - } else {
60 - t1 = $[1];
61 - }
62 - const [bar] = useState(t1);
63 - let t2;
64 - let t3;
65 - if ($[2] !== bar || $[3] !== foo) {
66 - t2 = () => {
67 - let isChanged = false;
68 - const newData = foo.map((val) => {
69 - bar.someMethod(val);
70 - isChanged = true;
71 - });
72 - if (isChanged) {
73 - setFoo(newData);
74 - }
75 - };
76 - t3 = [foo, bar];
77 - $[2] = bar;
78 - $[3] = foo;
79 - $[4] = t2;
80 - $[5] = t3;
81 - } else {
82 - t2 = $[4];
83 - t3 = $[5];
84 - }
85 - useEffect(t2, t3);
86 - let t4;
87 - if ($[6] !== bar || $[7] !== foo) {
88 - t4 = (
89 - <div>
90 - {foo}, {bar}
91 - </div>
92 - );
93 - $[6] = bar;
94 - $[7] = foo;
95 - $[8] = t4;
96 - } else {
97 - t4 = $[8];
98 - }
99 - return t4;
46 + const [foo, setFoo] = useState({});
47 + const [bar, setBar] = useState(new Set());
48 +
49 + /*
50 + * isChanged is considered context of the effect's function expression,
51 + * if we don't bail out of effect mutation derivation tracking, isChanged
52 + * will inherit the sources of the effect's function expression.
53 + *
54 + * This is innacurate and with the multiple passes ends up causing an infinite loop.
55 + */
56 + useEffect(() => {
57 + let isChanged = false;
58 +
59 + const newData = foo.map((val) => {
60 + bar.someMethod(val);
61 + isChanged = true;
62 + });
63 +
64 + if (isChanged) {
65 + setFoo(newData);
66 + }
67 + }, [foo, bar]);
68 +
69 + return (
70 + <div>
71 + {foo}, {bar}
72 + </div>
73 + );
74 }
75
76 ```
@@ -104,8 +78,8 @@ function Component() {
78 ## Logs
79
80 ```
107 -{"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: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (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":23,"column":6,"index":663},"end":{"line":23,"column":12,"index":669},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
108 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":32,"column":1,"index":762},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
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\nState: [foo, bar]\n\nData Flow Tree:\n└── newData\n ├── foo (State)\n └── bar (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":23,"column":6,"index":682},"end":{"line":23,"column":12,"index":688},"filename":"function-expression-mutation-edge-case.ts","identifierName":"setFoo"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
82 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":32,"column":1,"index":781},"filename":"function-expression-mutation-edge-case.ts"},"fnName":"Component","memoSlots":9,"memoBlocks":4,"memoValues":5,"prunedMemoBlocks":0,"prunedMemoValues":0}
83 ```
84
85 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
2
3 function Component() {
4 const [foo, setFoo] = useState({});
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md
+12 -30
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component() {
@@ -28,38 +28,20 @@ export const FIXTURE_ENTRYPOINT = {
28 ## Code
29
30 ```javascript
31 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
31 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
32 import { useEffect, useState } from "react";
33
34 function Component() {
35 - const $ = _c(5);
36 - const [firstName] = useState("Taylor");
35 + const [firstName, setFirstName] = useState("Taylor");
36 + const lastName = "Swift";
37
38 + // 🔴 Avoid: redundant state and unnecessary Effect
39 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;
40 + useEffect(() => {
41 + setFullName(firstName + " " + lastName);
42 + }, [firstName, lastName]);
43 +
44 + return <div>{fullName}</div>;
45 }
46
47 export const FIXTURE_ENTRYPOINT = {
@@ -72,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = {
54 ## Logs
55
56 ```
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}
57 +{"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":360},"end":{"line":11,"column":15,"index":371},"filename":"invalid-derived-computation-in-effect.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
58 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":126},"end":{"line":15,"column":1,"index":464},"filename":"invalid-derived-computation-in-effect.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
59 ```
60
61 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+11 -32
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 export default function Component(props) {
@@ -26,39 +26,18 @@ export const FIXTURE_ENTRYPOINT = {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
30 import { useEffect, useState } from "react";
31
32 export default function Component(props) {
33 - const $ = _c(7);
33 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;
34 +
35 + useEffect(() => {
36 + const computed = props.prefix + props.value + props.suffix;
37 + setDisplayValue(computed);
38 + }, [props.prefix, props.value, props.suffix]);
39 +
40 + return <div>{displayValue}</div>;
41 }
42
43 export const FIXTURE_ENTRYPOINT = {
@@ -71,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = {
50 ## Logs
51
52 ```
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}
53 +{"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":314},"end":{"line":9,"column":19,"index":329},"filename":"invalid-derived-state-from-computed-props.ts","identifierName":"setDisplayValue"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
54 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":13,"column":1,"index":428},"filename":"invalid-derived-state-from-computed-props.ts"},"fnName":"Component","memoSlots":7,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
55 ```
56
57 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+11 -32
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 export default function Component({props}) {
@@ -27,40 +27,19 @@ export const FIXTURE_ENTRYPOINT = {
27 ## Code
28
29 ```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
30 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
31 import { useEffect, useState } from "react";
32
33 -export default function Component(t0) {
34 - const $ = _c(6);
35 - const { props } = t0;
33 +export default function Component({ props }) {
34 const [fullName, setFullName] = useState(
35 props.firstName + " " + props.lastName,
36 );
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;
37 +
38 + useEffect(() => {
39 + setFullName(props.firstName + " " + props.lastName);
40 + }, [props.firstName, props.lastName]);
41 +
42 + return <div>{fullName}</div>;
43 }
44
45 export const FIXTURE_ENTRYPOINT = {
@@ -73,8 +52,8 @@ export const FIXTURE_ENTRYPOINT = {
52 ## Logs
53
54 ```
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}
55 +{"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":288},"end":{"line":10,"column":15,"index":299},"filename":"invalid-derived-state-from-destructured-props.ts","identifierName":"setFullName"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
56 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":141},"end":{"line":14,"column":1,"index":416},"filename":"invalid-derived-state-from-destructured-props.ts"},"fnName":"Component","memoSlots":6,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
57 ```
58
59 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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
+14 -34
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6 import {useEffect, useState, useRef} from 'react';
7
8 export default function Component({test}) {
@@ -31,43 +31,23 @@ export const FIXTURE_ENTRYPOINT = {
31 ## Code
32
33 ```javascript
34 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
34 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
35 import { useEffect, useState, useRef } from "react";
36
37 -export default function Component(t0) {
38 - const $ = _c(5);
39 - const { test } = t0;
37 +export default function Component({ test }) {
38 const [local, setLocal] = useState(0);
39
40 const myRef = useRef(null);
43 - let t1;
44 - let t2;
45 - if ($[0] !== test) {
46 - t1 = () => {
47 - if (myRef.current) {
48 - setLocal(test);
49 - } else {
50 - setLocal(test + test);
51 - }
52 - };
53 - t2 = [test];
54 - $[0] = test;
55 - $[1] = t1;
56 - $[2] = t2;
57 - } else {
58 - t1 = $[1];
59 - t2 = $[2];
60 - }
61 - useEffect(t1, t2);
62 - let t3;
63 - if ($[3] !== local) {
64 - t3 = <>{local}</>;
65 - $[3] = local;
66 - $[4] = t3;
67 - } else {
68 - t3 = $[4];
69 - }
70 - return t3;
41 +
42 + useEffect(() => {
43 + if (myRef.current) {
44 + setLocal(test);
45 + } else {
46 + setLocal(test + test);
47 + }
48 + }, [test]);
49 +
50 + return <>{local}</>;
51 }
52
53 export const FIXTURE_ENTRYPOINT = {
@@ -80,7 +60,7 @@ export const FIXTURE_ENTRYPOINT = {
60 ## Logs
61
62 ```
83 -{"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}
63 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":15,"index":149},"end":{"line":18,"column":1,"index":405},"filename":"ref-conditional-in-effect-no-error.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
64 ```
65
66 ### Eval output
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 @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
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/usestate-derived-from-prop-no-show-in-data-flow-tree.expect.md
+18 -32
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
5 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
6
7 function Component({prop}) {
8 const [s, setS] = useState();
@@ -26,37 +26,23 @@ function Component({prop}) {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
29 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
30
31 -function Component(t0) {
32 - const $ = _c(5);
33 - const { prop } = t0;
31 +function Component({ prop }) {
32 const [s, setS] = useState();
35 - const [second] = useState(prop);
36 - let t1;
37 - let t2;
38 - if ($[0] !== second) {
39 - t1 = () => {
40 - setS(second);
41 - };
42 - t2 = [second];
43 - $[0] = second;
44 - $[1] = t1;
45 - $[2] = t2;
46 - } else {
47 - t1 = $[1];
48 - t2 = $[2];
49 - }
50 - useEffect(t1, t2);
51 - let t3;
52 - if ($[3] !== s) {
53 - t3 = <div>{s}</div>;
54 - $[3] = s;
55 - $[4] = t3;
56 - } else {
57 - t3 = $[4];
58 - }
59 - return t3;
33 + const [second, setSecond] = useState(prop);
34 +
35 + /*
36 + * `second` is a source of state. It will inherit the value of `prop` in
37 + * the first render, but after that it will no longer be updated when
38 + * `prop` changes. So we shouldn't consider `second` as being derived from
39 + * `prop`
40 + */
41 + useEffect(() => {
42 + setS(second);
43 + }, [second]);
44 +
45 + return <div>{s}</div>;
46 }
47
48 ```
@@ -64,8 +50,8 @@ function Component(t0) {
50 ## Logs
51
52 ```
67 -{"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: [second]\n\nData Flow Tree:\n└── second (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":14,"column":4,"index":443},"end":{"line":14,"column":8,"index":447},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
68 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":64},"end":{"line":18,"column":1,"index":500},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 +{"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: [second]\n\nData Flow Tree:\n└── second (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":14,"column":4,"index":462},"end":{"line":14,"column":8,"index":466},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts","identifierName":"setS"},"message":"This should be computed during render, not in an effect"}]}},"fnLoc":null}
54 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":3,"column":0,"index":83},"end":{"line":18,"column":1,"index":519},"filename":"usestate-derived-from-prop-no-show-in-data-flow-tree.ts"},"fnName":"Component","memoSlots":5,"memoBlocks":2,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
55 ```
56
57 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/usestate-derived-from-prop-no-show-in-data-flow-tree.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly
1 +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint"
2
3 function Component({prop}) {
4 const [s, setS] = useState();
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md
+1 -1
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoJSXInTryStatements
5 +// @validateNoJSXInTryStatements @outputMode:"lint"
6 import {identity} from 'shared-runtime';
7
8 function Component(props) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoJSXInTryStatements
1 +// @validateNoJSXInTryStatements @outputMode:"lint"
2 import {identity} from 'shared-runtime';
3
4 function Component(props) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md
+1 -1
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoJSXInTryStatements
5 +// @validateNoJSXInTryStatements @outputMode:"lint"
6 function Component(props) {
7 let el;
8 try {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoJSXInTryStatements
1 +// @validateNoJSXInTryStatements @outputMode:"lint"
2 function Component(props) {
3 let el;
4 try {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md
+6 -23
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateNoJSXInTryStatements
5 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
6 import {identity} from 'shared-runtime';
7
8 function Component(props) {
@@ -25,34 +25,17 @@ function Component(props) {
25 ## Code
26
27 ```javascript
28 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoJSXInTryStatements
28 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
29 import { identity } from "shared-runtime";
30
31 function Component(props) {
32 - const $ = _c(4);
32 let el;
33 try {
34 let value;
35 try {
37 - let t0;
38 - if ($[0] !== props.foo) {
39 - t0 = identity(props.foo);
40 - $[0] = props.foo;
41 - $[1] = t0;
42 - } else {
43 - t0 = $[1];
44 - }
45 - value = t0;
36 + value = identity(props.foo);
37 } catch {
47 - let t0;
48 - if ($[2] !== value) {
49 - t0 = <div value={value} />;
50 - $[2] = value;
51 - $[3] = t0;
52 - } else {
53 - t0 = $[3];
54 - }
55 - el = t0;
38 + el = <div value={value} />;
39 }
40 } catch {
41 return null;
@@ -65,8 +48,8 @@ function Component(props) {
48 ## Logs
49
50 ```
68 -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"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}
51 +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"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":241},"end":{"line":11,"column":32,"index":262},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
52 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":110},"end":{"line":17,"column":1,"index":317},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
54
55 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateNoJSXInTryStatements
1 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
2 import {identity} from 'shared-runtime';
3
4 function Component(props) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md
+5 -13
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateNoJSXInTryStatements
5 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
6 function Component(props) {
7 let el;
8 try {
@@ -18,19 +18,11 @@ function Component(props) {
18 ## Code
19
20 ```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoJSXInTryStatements
21 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
22 function Component(props) {
23 - const $ = _c(1);
23 let el;
24 try {
26 - let t0;
27 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 - t0 = <div />;
29 - $[0] = t0;
30 - } else {
31 - t0 = $[0];
32 - }
33 - el = t0;
25 + el = <div />;
26 } catch {
27 return null;
28 }
@@ -42,8 +34,8 @@ function Component(props) {
34 ## Logs
35
36 ```
45 -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"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}
37 +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"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":123},"end":{"line":5,"column":16,"index":130},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
38 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":68},"end":{"line":10,"column":1,"index":179},"filename":"invalid-jsx-in-try-with-catch.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
39 ```
40
41 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateNoJSXInTryStatements
1 +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint"
2 function Component(props) {
3 let el;
4 try {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md
+13 -31
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateNoSetStateInEffects
5 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component() {
@@ -24,48 +24,30 @@ function Component() {
24 ## Code
25
26 ```javascript
27 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoSetStateInEffects
27 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
28 import { useEffect, useState } from "react";
29
30 function Component() {
31 - const $ = _c(2);
31 const [state, setState] = useState(0);
33 - let t0;
34 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
35 - const f = () => {
36 - setState(_temp);
37 - };
38 - t0 = () => {
39 - f();
40 - };
41 - $[0] = t0;
42 - } else {
43 - t0 = $[0];
44 - }
45 - const g = t0;
46 - let t1;
47 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
48 - t1 = () => {
49 - g();
50 - };
51 - $[1] = t1;
52 - } else {
53 - t1 = $[1];
54 - }
55 - useEffect(t1);
32 + const f = () => {
33 + setState((s) => s + 1);
34 + };
35 + const g = () => {
36 + f();
37 + };
38 + useEffect(() => {
39 + g();
40 + });
41 return state;
42 }
58 -function _temp(s) {
59 - return s + 1;
60 -}
43
44 ```
45
46 ## Logs
47
48 ```
67 -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","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() directly within an effect"}]}},"fnLoc":null}
68 -{"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}
49 +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":284},"end":{"line":13,"column":5,"index":285},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
50 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":16,"column":1,"index":312},"filename":"invalid-setState-in-useEffect-transitive.ts"},"fnName":"Component","memoSlots":2,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
51 ```
52
53 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateNoSetStateInEffects
1 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
2 import {useEffect, useState} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-via-useEffectEvent.expect.md
+10 -33
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateNoSetStateInEffects
5 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
6 import {useEffect, useEffectEvent, useState} from 'react';
7
8 function Component() {
@@ -21,40 +21,17 @@ function Component() {
21 ## Code
22
23 ```javascript
24 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoSetStateInEffects
24 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
25 import { useEffect, useEffectEvent, useState } from "react";
26
27 function Component() {
28 - const $ = _c(4);
28 const [state, setState] = useState(0);
30 - let t0;
31 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
32 - t0 = () => {
33 - setState(true);
34 - };
35 - $[0] = t0;
36 - } else {
37 - t0 = $[0];
38 - }
39 - const effectEvent = useEffectEvent(t0);
40 - let t1;
41 - if ($[1] !== effectEvent) {
42 - t1 = () => {
43 - effectEvent();
44 - };
45 - $[1] = effectEvent;
46 - $[2] = t1;
47 - } else {
48 - t1 = $[2];
49 - }
50 - let t2;
51 - if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
52 - t2 = [];
53 - $[3] = t2;
54 - } else {
55 - t2 = $[3];
56 - }
57 - useEffect(t1, t2);
29 + const effectEvent = useEffectEvent(() => {
30 + setState(true);
31 + });
32 + useEffect(() => {
33 + effectEvent();
34 + }, []);
35 return state;
36 }
37
@@ -63,8 +40,8 @@ function Component() {
40 ## Logs
41
42 ```
66 -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":267},"end":{"line":10,"column":15,"index":278},"filename":"invalid-setState-in-useEffect-via-useEffectEvent.ts","identifierName":"effectEvent"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
67 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":108},"end":{"line":13,"column":1,"index":309},"filename":"invalid-setState-in-useEffect-via-useEffectEvent.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
43 +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":10,"column":4,"index":286},"end":{"line":10,"column":15,"index":297},"filename":"invalid-setState-in-useEffect-via-useEffectEvent.ts","identifierName":"effectEvent"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
44 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":127},"end":{"line":13,"column":1,"index":328},"filename":"invalid-setState-in-useEffect-via-useEffectEvent.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":3,"memoValues":3,"prunedMemoBlocks":0,"prunedMemoValues":0}
45 ```
46
47 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-via-useEffectEvent.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateNoSetStateInEffects
1 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
2 import {useEffect, useEffectEvent, useState} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md
+7 -18
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateNoSetStateInEffects
5 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component() {
@@ -18,35 +18,24 @@ function Component() {
18 ## Code
19
20 ```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoSetStateInEffects
21 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
22 import { useEffect, useState } from "react";
23
24 function Component() {
25 - const $ = _c(1);
25 const [state, setState] = useState(0);
27 - let t0;
28 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
29 - t0 = () => {
30 - setState(_temp);
31 - };
32 - $[0] = t0;
33 - } else {
34 - t0 = $[0];
35 - }
36 - useEffect(t0);
26 + useEffect(() => {
27 + setState((s) => s + 1);
28 + });
29 return state;
30 }
39 -function _temp(s) {
40 - return s + 1;
41 -}
31
32 ```
33
34 ## Logs
35
36 ```
48 -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","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() directly within 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}
37 +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":199},"end":{"line":7,"column":12,"index":207},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
38 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":10,"column":1,"index":244},"filename":"invalid-setState-in-useEffect.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
39 ```
40
41 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateNoSetStateInEffects
1 +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint"
2 import {useEffect, useState} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md
+6 -22
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateStaticComponents
5 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
6 function Example(props) {
7 let Component;
8 if (props.cond) {
@@ -18,31 +18,15 @@ function Example(props) {
18 ## Code
19
20 ```javascript
21 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents
21 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
22 function Example(props) {
23 - const $ = _c(3);
23 let Component;
24 if (props.cond) {
26 - let t0;
27 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28 - t0 = createComponent();
29 - $[0] = t0;
30 - } else {
31 - t0 = $[0];
32 - }
33 - Component = t0;
25 + Component = createComponent();
26 } else {
27 Component = DefaultComponent;
28 }
37 - let t0;
38 - if ($[1] !== Component) {
39 - t0 = <Component />;
40 - $[1] = Component;
41 - $[2] = t0;
42 - } else {
43 - t0 = $[2];
44 - }
45 - return t0;
29 + return <Component />;
30 }
31
32 ```
@@ -50,8 +34,8 @@ function Example(props) {
34 ## Logs
35
36 ```
53 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":202},"end":{"line":9,"column":19,"index":211},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":124},"end":{"line":5,"column":33,"index":141},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
54 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":10,"column":1,"index":217},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"fnName":"Example","memoSlots":3,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
37 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":221},"end":{"line":9,"column":19,"index":230},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":143},"end":{"line":5,"column":33,"index":160},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
38 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":64},"end":{"line":10,"column":1,"index":236},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"fnName":"Example","memoSlots":3,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
39 ```
40
41 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateStaticComponents
1 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
2 function Example(props) {
3 let Component;
4 if (props.cond) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md
+6 -14
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateStaticComponents
5 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
6 function Example(props) {
7 const Component = createComponent();
8 return <Component />;
@@ -13,18 +13,10 @@ function Example(props) {
13 ## Code
14
15 ```javascript
16 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents
16 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
17 function Example(props) {
18 - const $ = _c(1);
19 - let t0;
20 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 - const Component = createComponent();
22 - t0 = <Component />;
23 - $[0] = t0;
24 - } else {
25 - t0 = $[0];
26 - }
27 - return t0;
18 + const Component = createComponent();
19 + return <Component />;
20 }
21
22 ```
@@ -32,8 +24,8 @@ function Example(props) {
24 ## Logs
25
26 ```
35 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":120},"end":{"line":4,"column":19,"index":129},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":37,"index":108},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
36 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":135},"filename":"invalid-dynamically-construct-component-in-render.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
27 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":139},"end":{"line":4,"column":19,"index":148},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":110},"end":{"line":3,"column":37,"index":127},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
28 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":64},"end":{"line":5,"column":1,"index":154},"filename":"invalid-dynamically-construct-component-in-render.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
29 ```
30
31 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateStaticComponents
1 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
2 function Example(props) {
3 const Component = createComponent();
4 return <Component />;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md
+7 -15
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateStaticComponents
5 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
6 function Example(props) {
7 function Component() {
8 return <div />;
@@ -15,20 +15,12 @@ function Example(props) {
15 ## Code
16
17 ```javascript
18 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents
18 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
19 function Example(props) {
20 - const $ = _c(1);
21 - let t0;
22 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
23 - const Component = function Component() {
24 - return <div />;
25 - };
26 - t0 = <Component />;
27 - $[0] = t0;
28 - } else {
29 - t0 = $[0];
20 + function Component() {
21 + return <div />;
22 }
31 - return t0;
23 + return <Component />;
24 }
25
26 ```
@@ -36,8 +28,8 @@ function Example(props) {
28 ## Logs
29
30 ```
39 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":130},"end":{"line":6,"column":19,"index":139},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":73},"end":{"line":5,"column":3,"index":119},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
40 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":7,"column":1,"index":145},"filename":"invalid-dynamically-constructed-component-function.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
31 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":149},"end":{"line":6,"column":19,"index":158},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":92},"end":{"line":5,"column":3,"index":138},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
32 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":64},"end":{"line":7,"column":1,"index":164},"filename":"invalid-dynamically-constructed-component-function.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
33 ```
34
35 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateStaticComponents
1 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
2 function Example(props) {
3 function Component() {
4 return <div />;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md
+6 -23
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateStaticComponents
5 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
6 function Example(props) {
7 const Component = props.foo.bar();
8 return <Component />;
@@ -13,27 +13,10 @@ function Example(props) {
13 ## Code
14
15 ```javascript
16 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents
16 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
17 function Example(props) {
18 - const $ = _c(4);
19 - let t0;
20 - if ($[0] !== props.foo) {
21 - t0 = props.foo.bar();
22 - $[0] = props.foo;
23 - $[1] = t0;
24 - } else {
25 - t0 = $[1];
26 - }
27 - const Component = t0;
28 - let t1;
29 - if ($[2] !== Component) {
30 - t1 = <Component />;
31 - $[2] = Component;
32 - $[3] = t1;
33 - } else {
34 - t1 = $[3];
35 - }
36 - return t1;
18 + const Component = props.foo.bar();
19 + return <Component />;
20 }
21
22 ```
@@ -41,8 +24,8 @@ function Example(props) {
24 ## Logs
25
26 ```
44 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":118},"end":{"line":4,"column":19,"index":127},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":35,"index":106},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
45 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":133},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"fnName":"Example","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
27 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":137},"end":{"line":4,"column":19,"index":146},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":110},"end":{"line":3,"column":35,"index":125},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
28 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":64},"end":{"line":5,"column":1,"index":152},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"fnName":"Example","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
29 ```
30
31 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateStaticComponents
1 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
2 function Example(props) {
3 const Component = props.foo.bar();
4 return <Component />;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md
+6 -14
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @loggerTestOnly @validateStaticComponents
5 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
6 function Example(props) {
7 const Component = new ComponentFactory();
8 return <Component />;
@@ -13,18 +13,10 @@ function Example(props) {
13 ## Code
14
15 ```javascript
16 -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents
16 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
17 function Example(props) {
18 - const $ = _c(1);
19 - let t0;
20 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 - const Component = new ComponentFactory();
22 - t0 = <Component />;
23 - $[0] = t0;
24 - } else {
25 - t0 = $[0];
26 - }
27 - return t0;
18 + const Component = new ComponentFactory();
19 + return <Component />;
20 }
21
22 ```
@@ -32,8 +24,8 @@ function Example(props) {
24 ## Logs
25
26 ```
35 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":125},"end":{"line":4,"column":19,"index":134},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":42,"index":113},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
36 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":140},"filename":"invalid-dynamically-constructed-component-new.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
27 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":144},"end":{"line":4,"column":19,"index":153},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":110},"end":{"line":3,"column":42,"index":132},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
28 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":64},"end":{"line":5,"column":1,"index":159},"filename":"invalid-dynamically-constructed-component-new.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
29 ```
30
31 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @loggerTestOnly @validateStaticComponents
1 +// @loggerTestOnly @validateStaticComponents @outputMode:"lint"
2 function Example(props) {
3 const Component = new ComponentFactory();
4 return <Component />;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.expect.md
+8 -18
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects
5 +// @validateNoSetStateInEffects @outputMode:"lint"
6 import {useState, useRef, useEffect} from 'react';
7
8 function Tooltip() {
@@ -27,28 +27,18 @@ export const FIXTURE_ENTRYPOINT = {
27 ## Code
28
29 ```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects
30 +// @validateNoSetStateInEffects @outputMode:"lint"
31 import { useState, useRef, useEffect } from "react";
32
33 function Tooltip() {
34 - const $ = _c(2);
34 const ref = useRef(null);
35 const [tooltipHeight, setTooltipHeight] = useState(0);
37 - let t0;
38 - let t1;
39 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40 - t0 = () => {
41 - const { height } = ref.current.getBoundingClientRect();
42 - setTooltipHeight(height);
43 - };
44 - t1 = [];
45 - $[0] = t0;
46 - $[1] = t1;
47 - } else {
48 - t0 = $[0];
49 - t1 = $[1];
50 - }
51 - useEffect(t0, t1);
36 +
37 + useEffect(() => {
38 + const { height } = ref.current.getBoundingClientRect();
39 + setTooltipHeight(height);
40 + }, []);
41 +
42 return tooltipHeight;
43 }
44
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects
1 +// @validateNoSetStateInEffects @outputMode:"lint"
2 import {useState, useRef, useEffect} from 'react';
3
4 function Tooltip() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.expect.md
+8 -25
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
5 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
6 import {useState, useRef, useLayoutEffect} from 'react';
7
8 function Component() {
@@ -26,34 +26,17 @@ export const FIXTURE_ENTRYPOINT = {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
29 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
30 import { useState, useRef, useLayoutEffect } from "react";
31
32 function Component() {
33 - const $ = _c(3);
34 - let t0;
35 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
36 - t0 = { size: 5 };
37 - $[0] = t0;
38 - } else {
39 - t0 = $[0];
40 - }
41 - const ref = useRef(t0);
33 + const ref = useRef({ size: 5 });
34 const [computedSize, setComputedSize] = useState(0);
43 - let t1;
44 - let t2;
45 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
46 - t1 = () => {
47 - setComputedSize(ref.current.size * 10);
48 - };
49 - t2 = [];
50 - $[1] = t1;
51 - $[2] = t2;
52 - } else {
53 - t1 = $[1];
54 - t2 = $[2];
55 - }
56 - useLayoutEffect(t1, t2);
35 +
36 + useLayoutEffect(() => {
37 + setComputedSize(ref.current.size * 10);
38 + }, []);
39 +
40 return computedSize;
41 }
42
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
1 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
2 import {useState, useRef, useLayoutEffect} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.expect.md
+9 -25
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
5 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
6 import {useState, useRef, useEffect} from 'react';
7
8 function Component() {
@@ -27,34 +27,18 @@ export const FIXTURE_ENTRYPOINT = {
27 ## Code
28
29 ```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
30 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
31 import { useState, useRef, useEffect } from "react";
32
33 function Component() {
34 - const $ = _c(3);
35 - let t0;
36 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
37 - t0 = [1, 2, 3, 4, 5];
38 - $[0] = t0;
39 - } else {
40 - t0 = $[0];
41 - }
42 - const ref = useRef(t0);
34 + const ref = useRef([1, 2, 3, 4, 5]);
35 const [value, setValue] = useState(0);
44 - let t1;
45 - let t2;
46 - if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
47 - t1 = () => {
48 - setValue(ref.current[2]);
49 - };
50 - t2 = [];
51 - $[1] = t1;
52 - $[2] = t2;
53 - } else {
54 - t1 = $[1];
55 - t2 = $[2];
56 - }
57 - useEffect(t1, t2);
36 +
37 + useEffect(() => {
38 + const index = 2;
39 + setValue(ref.current[index]);
40 + }, []);
41 +
42 return value;
43 }
44
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
1 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
2 import {useState, useRef, useEffect} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.expect.md
+14 -23
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
5 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
6 import {useState, useRef, useEffect} from 'react';
7
8 function Component() {
@@ -33,33 +33,24 @@ export const FIXTURE_ENTRYPOINT = {
33 ## Code
34
35 ```javascript
36 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
36 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
37 import { useState, useRef, useEffect } from "react";
38
39 function Component() {
40 - const $ = _c(2);
40 const ref = useRef(null);
41 const [width, setWidth] = useState(0);
43 - let t0;
44 - let t1;
45 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
46 - t0 = () => {
47 - const getBoundingRect = function getBoundingRect(ref_0) {
48 - if (ref_0.current) {
49 - return ref_0.current.getBoundingClientRect?.()?.width ?? 100;
50 - }
51 - return 100;
52 - };
53 - setWidth(getBoundingRect(ref));
54 - };
55 - t1 = [];
56 - $[0] = t0;
57 - $[1] = t1;
58 - } else {
59 - t0 = $[0];
60 - t1 = $[1];
61 - }
62 - useEffect(t0, t1);
42 +
43 + useEffect(() => {
44 + function getBoundingRect(ref_0) {
45 + if (ref_0.current) {
46 + return ref_0.current.getBoundingClientRect?.()?.width ?? 100;
47 + }
48 + return 100;
49 + }
50 +
51 + setWidth(getBoundingRect(ref));
52 + }, []);
53 +
54 return width;
55 }
56
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
1 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
2 import {useState, useRef, useEffect} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.expect.md
+16 -29
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer"
5 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint"
6 import {useState, useRef, useEffect} from 'react';
7
8 function Component({x, y}) {
@@ -48,39 +48,26 @@ export const FIXTURE_ENTRYPOINT = {
48 ## Code
49
50 ```javascript
51 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer"
51 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint"
52 import { useState, useRef, useEffect } from "react";
53
54 -function Component(t0) {
55 - const $ = _c(4);
56 - const { x, y } = t0;
54 +function Component({ x, y }) {
55 const previousXRef = useRef(null);
56 const previousYRef = useRef(null);
57
58 const [data, setData] = useState(null);
61 - let t1;
62 - let t2;
63 - if ($[0] !== x || $[1] !== y) {
64 - t1 = () => {
65 - const previousX = previousXRef.current;
66 - previousXRef.current = x;
67 - const previousY = previousYRef.current;
68 - previousYRef.current = y;
69 - if (!areEqual(x, previousX) || !areEqual(y, previousY)) {
70 - const data_0 = load({ x, y });
71 - setData(data_0);
72 - }
73 - };
74 - t2 = [x, y];
75 - $[0] = x;
76 - $[1] = y;
77 - $[2] = t1;
78 - $[3] = t2;
79 - } else {
80 - t1 = $[2];
81 - t2 = $[3];
82 - }
83 - useEffect(t1, t2);
59 +
60 + useEffect(() => {
61 + const previousX = previousXRef.current;
62 + previousXRef.current = x;
63 + const previousY = previousYRef.current;
64 + previousYRef.current = y;
65 + if (!areEqual(x, previousX) || !areEqual(y, previousY)) {
66 + const data_0 = load({ x, y });
67 + setData(data_0);
68 + }
69 + }, [x, y]);
70 +
71 return data;
72 }
73
@@ -107,7 +94,7 @@ export const FIXTURE_ENTRYPOINT = {
94 ## Logs
95
96 ```
110 -{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":163},"end":{"line":22,"column":1,"index":631},"filename":"valid-setState-in-useEffect-controlled-by-ref-value.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":1,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
97 +{"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":182},"end":{"line":22,"column":1,"index":650},"filename":"valid-setState-in-useEffect-controlled-by-ref-value.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":1,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
98 ```
99
100 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer"
1 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint"
2 import {useState, useRef, useEffect} from 'react';
3
4 function Component({x, y}) {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.expect.md
+7 -16
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects
5 +// @validateNoSetStateInEffects @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component() {
@@ -26,26 +26,17 @@ export const FIXTURE_ENTRYPOINT = {
26 ## Code
27
28 ```javascript
29 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects
29 +// @validateNoSetStateInEffects @outputMode:"lint"
30 import { useEffect, useState } from "react";
31
32 function Component() {
33 - const $ = _c(1);
33 const [state, setState] = useState(0);
35 - let t0;
36 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
37 - t0 = () => {
38 - const f = () => {
39 - setState();
40 - };
41 -
42 - setTimeout(() => f(), 10);
34 + useEffect(() => {
35 + const f = () => {
36 + setState();
37 };
44 - $[0] = t0;
45 - } else {
46 - t0 = $[0];
47 - }
48 - useEffect(t0);
38 + setTimeout(() => f(), 10);
39 + });
40 return state;
41 }
42
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects
1 +// @validateNoSetStateInEffects @outputMode:"lint"
2 import {useEffect, useState} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.expect.md
+5 -13
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects
5 +// @validateNoSetStateInEffects @outputMode:"lint"
6 import {useEffect, useState} from 'react';
7
8 function Component() {
@@ -23,22 +23,14 @@ export const FIXTURE_ENTRYPOINT = {
23 ## Code
24
25 ```javascript
26 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects
26 +// @validateNoSetStateInEffects @outputMode:"lint"
27 import { useEffect, useState } from "react";
28
29 function Component() {
30 - const $ = _c(1);
30 const [state, setState] = useState(0);
32 - let t0;
33 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
34 - t0 = () => {
35 - setTimeout(setState, 10);
36 - };
37 - $[0] = t0;
38 - } else {
39 - t0 = $[0];
40 - }
41 - useEffect(t0);
31 + useEffect(() => {
32 + setTimeout(setState, 10);
33 + });
34 return state;
35 }
36
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects
1 +// @validateNoSetStateInEffects @outputMode:"lint"
2 import {useEffect, useState} from 'react';
3
4 function Component() {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.expect.md
+8 -18
@@ -2,7 +2,7 @@
2 ## Input
3
4 ```javascript
5 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
5 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
6 import {useState, useRef, useLayoutEffect} from 'react';
7
8 function Tooltip() {
@@ -27,28 +27,18 @@ export const FIXTURE_ENTRYPOINT = {
27 ## Code
28
29 ```javascript
30 -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
30 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
31 import { useState, useRef, useLayoutEffect } from "react";
32
33 function Tooltip() {
34 - const $ = _c(2);
34 const ref = useRef(null);
35 const [tooltipHeight, setTooltipHeight] = useState(0);
37 - let t0;
38 - let t1;
39 - if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40 - t0 = () => {
41 - const { height } = ref.current.getBoundingClientRect();
42 - setTooltipHeight(height);
43 - };
44 - t1 = [];
45 - $[0] = t0;
46 - $[1] = t1;
47 - } else {
48 - t0 = $[0];
49 - t1 = $[1];
50 - }
51 - useLayoutEffect(t0, t1);
36 +
37 + useLayoutEffect(() => {
38 + const { height } = ref.current.getBoundingClientRect();
39 + setTooltipHeight(height);
40 + }, []);
41 +
42 return tooltipHeight;
43 }
44
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.js
+1 -1
@@ -1,4 +1,4 @@
1 -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects
1 +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
2 import {useState, useRef, useLayoutEffect} from 'react';
3
4 function Tooltip() {