From f98f910f5f4ad0b34c725bb01204e5a9958de089 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Tue, 25 Nov 2025 16:21:40 -0800 Subject: [PATCH] [compiler] Only run validations with env.logErrors on outputMode: 'lint' 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 --- .../src/Entrypoint/Pipeline.ts | 15 ++- ...ed-state-conditionally-in-effect.expect.md | 52 +++-------- .../derived-state-conditionally-in-effect.js | 2 +- ...derived-state-from-default-props.expect.md | 44 +++------ .../derived-state-from-default-props.js | 2 +- ...state-from-local-state-in-effect.expect.md | 51 +++------- ...erived-state-from-local-state-in-effect.js | 2 +- ...-local-state-and-component-scope.expect.md | 79 ++++------------ ...om-prop-local-state-and-component-scope.js | 2 +- ...ter-call-outside-effect-no-error.expect.md | 55 +++-------- ...rop-setter-call-outside-effect-no-error.js | 2 +- ...d-state-from-prop-setter-ternary.expect.md | 38 ++------ .../derived-state-from-prop-setter-ternary.js | 2 +- ...ter-used-outside-effect-no-error.expect.md | 56 +++-------- ...rop-setter-used-outside-effect-no-error.js | 2 +- ...state-from-prop-with-side-effect.expect.md | 44 +++------ ...erived-state-from-prop-with-side-effect.js | 2 +- ...tate-from-ref-and-state-no-error.expect.md | 40 ++------ ...rived-state-from-ref-and-state-no-error.js | 2 +- ...ect-contains-local-function-call.expect.md | 56 +++-------- .../effect-contains-local-function-call.js | 2 +- ...ains-prop-function-call-no-error.expect.md | 48 +++------- ...ct-contains-prop-function-call-no-error.js | 2 +- ...t-used-in-dep-array-still-errors.expect.md | 45 +++------ .../effect-used-in-dep-array-still-errors.js | 2 +- ...ing-on-derived-computation-value.expect.md | 49 ++++------ ...-depending-on-derived-computation-value.js | 2 +- ...th-global-function-call-no-error.expect.md | 41 ++------ ...fect-with-global-function-call-no-error.js | 2 +- ...rops-setstate-in-effect-no-error.expect.md | 44 ++------- .../from-props-setstate-in-effect-no-error.js | 2 +- ...on-expression-mutation-edge-case.expect.md | 93 +++++++------------ .../function-expression-mutation-edge-case.js | 2 +- ...id-derived-computation-in-effect.expect.md | 42 +++------ .../invalid-derived-computation-in-effect.js | 2 +- ...erived-state-from-computed-props.expect.md | 43 +++------ ...valid-derived-state-from-computed-props.js | 2 +- ...ed-state-from-destructured-props.expect.md | 43 +++------ ...d-derived-state-from-destructured-props.js | 2 +- ...f-conditional-in-effect-no-error.expect.md | 49 +++------- .../ref-conditional-in-effect-no-error.js | 2 +- ...m-prop-no-show-in-data-flow-tree.expect.md | 50 ++++------ ...ved-from-prop-no-show-in-data-flow-tree.js | 2 +- ...-catch-in-outer-try-with-finally.expect.md | 2 +- ...-jsx-in-catch-in-outer-try-with-finally.js | 2 +- ...-invalid-jsx-in-try-with-finally.expect.md | 2 +- ...or.todo-invalid-jsx-in-try-with-finally.js | 2 +- ...in-catch-in-outer-try-with-catch.expect.md | 29 ++---- ...id-jsx-in-catch-in-outer-try-with-catch.js | 2 +- .../invalid-jsx-in-try-with-catch.expect.md | 18 +--- .../compiler/invalid-jsx-in-try-with-catch.js | 2 +- ...setState-in-useEffect-transitive.expect.md | 45 +++------ ...nvalid-setState-in-useEffect-transitive.js | 2 +- .../invalid-setState-in-useEffect.expect.md | 25 ++--- .../compiler/invalid-setState-in-useEffect.js | 2 +- ...-constructed-component-in-render.expect.md | 28 ++---- ...mically-constructed-component-in-render.js | 2 +- ...ly-construct-component-in-render.expect.md | 20 ++-- ...namically-construct-component-in-render.js | 2 +- ...y-constructed-component-function.expect.md | 23 ++--- ...amically-constructed-component-function.js | 2 +- ...onstructed-component-method-call.expect.md | 29 ++---- ...cally-constructed-component-method-call.js | 2 +- ...ically-constructed-component-new.expect.md | 20 ++-- ...d-dynamically-constructed-component-new.js | 2 +- ...-set-state-in-useEffect-from-ref.expect.md | 26 ++---- .../valid-set-state-in-useEffect-from-ref.js | 2 +- ...te-in-effect-from-ref-arithmetic.expect.md | 33 ++----- ...-setState-in-effect-from-ref-arithmetic.js | 2 +- ...e-in-effect-from-ref-array-index.expect.md | 34 ++----- ...setState-in-effect-from-ref-array-index.js | 2 +- ...in-effect-from-ref-function-call.expect.md | 38 +++----- ...tState-in-effect-from-ref-function-call.js | 2 +- ...seEffect-controlled-by-ref-value.expect.md | 46 ++++----- ...te-in-useEffect-controlled-by-ref-value.js | 2 +- ...in-useEffect-listener-transitive.expect.md | 23 ++--- ...tState-in-useEffect-listener-transitive.js | 2 +- ...d-setState-in-useEffect-listener.expect.md | 18 +--- .../valid-setState-in-useEffect-listener.js | 2 +- ...tate-in-useLayoutEffect-from-ref.expect.md | 26 ++---- ...id-setState-in-useLayoutEffect-from-ref.js | 2 +- 81 files changed, 479 insertions(+), 1163 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 1b76dfb43e14a..62db05d348b64 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -279,17 +279,20 @@ function runWithEnvironment( validateNoSetStateInRender(hir).unwrap(); } - if (env.config.validateNoDerivedComputationsInEffects_exp) { + if ( + env.config.validateNoDerivedComputationsInEffects_exp && + env.outputMode === 'lint' + ) { env.logErrors(validateNoDerivedComputationsInEffects_exp(hir)); } else if (env.config.validateNoDerivedComputationsInEffects) { validateNoDerivedComputationsInEffects(hir); } - if (env.config.validateNoSetStateInEffects) { + if (env.config.validateNoSetStateInEffects && env.outputMode === 'lint') { env.logErrors(validateNoSetStateInEffects(hir, env)); } - if (env.config.validateNoJSXInTryStatements) { + if (env.config.validateNoJSXInTryStatements && env.outputMode === 'lint') { env.logErrors(validateNoJSXInTryStatement(hir)); } @@ -317,7 +320,11 @@ function runWithEnvironment( value: hir, }); - if (env.enableValidations && env.config.validateStaticComponents) { + if ( + env.enableValidations && + env.config.validateStaticComponents && + env.outputMode === 'lint' + ) { env.logErrors(validateStaticComponents(hir)); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md index 756a219e645a1..fa5ae370e67ee 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({value, enabled}) { @@ -29,43 +29,21 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(6); - const { value, enabled } = t0; +function Component({ value, enabled }) { const [localValue, setLocalValue] = useState(""); - let t1; - let t2; - if ($[0] !== enabled || $[1] !== value) { - t1 = () => { - if (enabled) { - setLocalValue(value); - } else { - setLocalValue("disabled"); - } - }; - - t2 = [value, enabled]; - $[0] = enabled; - $[1] = value; - $[2] = t1; - $[3] = t2; - } else { - t1 = $[2]; - t2 = $[3]; - } - useEffect(t1, t2); - let t3; - if ($[4] !== localValue) { - t3 =
{localValue}
; - $[4] = localValue; - $[5] = t3; - } else { - t3 = $[5]; - } - return t3; + + useEffect(() => { + if (enabled) { + setLocalValue(value); + } else { + setLocalValue("disabled"); + } + }, [value, enabled]); + + return
{localValue}
; } export const FIXTURE_ENTRYPOINT = { @@ -78,8 +56,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js index fb65cbfeb82bd..4cdcb53bb2364 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-conditionally-in-effect.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({value, enabled}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.expect.md index 2f3a3d0e61606..4db10f4df4cff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component({input = 'empty'}) { @@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -export default function Component(t0) { - const $ = _c(5); - const { input: t1 } = t0; - const input = t1 === undefined ? "empty" : t1; +export default function Component({ input = "empty" }) { const [currInput, setCurrInput] = useState(input); - let t2; - let t3; - if ($[0] !== input) { - t2 = () => { - setCurrInput(input + "local const"); - }; - t3 = [input, "local const"]; - $[0] = input; - $[1] = t2; - $[2] = t3; - } else { - t2 = $[1]; - t3 = $[2]; - } - useEffect(t2, t3); - let t4; - if ($[3] !== currInput) { - t4 =
{currInput}
; - $[3] = currInput; - $[4] = t4; - } else { - t4 = $[4]; - } - return t4; + const localConst = "local const"; + + useEffect(() => { + setCurrInput(input + localConst); + }, [input, localConst]); + + return
{currInput}
; } export const FIXTURE_ENTRYPOINT = { @@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js index 1de911c9b3791..9d559946beade 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-default-props.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component({input = 'empty'}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.expect.md index 37458dcea06c5..afddca39e9a7b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; @@ -23,45 +23,20 @@ function Component({shouldChange}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(7); - const { shouldChange } = t0; +function Component({ shouldChange }) { const [count, setCount] = useState(0); - let t1; - if ($[0] !== count || $[1] !== shouldChange) { - t1 = () => { - if (shouldChange) { - setCount(count + 1); - } - }; - $[0] = count; - $[1] = shouldChange; - $[2] = t1; - } else { - t1 = $[2]; - } - let t2; - if ($[3] !== count) { - t2 = [count]; - $[3] = count; - $[4] = t2; - } else { - t2 = $[4]; - } - useEffect(t1, t2); - let t3; - if ($[5] !== count) { - t3 =
{count}
; - $[5] = count; - $[6] = t3; - } else { - t3 = $[6]; - } - return t3; + + useEffect(() => { + if (shouldChange) { + setCount(count + 1); + } + }, [count]); + + return
{count}
; } ``` @@ -69,8 +44,8 @@ function Component(t0) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js index 79e65e4849a90..db84ab8be45f1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-local-state-in-effect.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.expect.md index fdcbccd3de5be..e1c33a6c73f40 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({firstName}) { @@ -33,68 +33,25 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(12); - const { firstName } = t0; +function Component({ firstName }) { const [lastName, setLastName] = useState("Doe"); const [fullName, setFullName] = useState("John"); - let t1; - let t2; - if ($[0] !== firstName || $[1] !== lastName) { - t1 = () => { - setFullName(firstName + " " + "D." + " " + lastName); - }; - t2 = [firstName, "D.", lastName]; - $[0] = firstName; - $[1] = lastName; - $[2] = t1; - $[3] = t2; - } else { - t1 = $[2]; - t2 = $[3]; - } - useEffect(t1, t2); - let t3; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { - t3 = (e) => setLastName(e.target.value); - $[4] = t3; - } else { - t3 = $[4]; - } - let t4; - if ($[5] !== lastName) { - t4 = ; - $[5] = lastName; - $[6] = t4; - } else { - t4 = $[6]; - } - let t5; - if ($[7] !== fullName) { - t5 =
{fullName}
; - $[7] = fullName; - $[8] = t5; - } else { - t5 = $[8]; - } - let t6; - if ($[9] !== t4 || $[10] !== t5) { - t6 = ( -
- {t4} - {t5} -
- ); - $[9] = t4; - $[10] = t5; - $[11] = t6; - } else { - t6 = $[11]; - } - return t6; + + const middleName = "D."; + + useEffect(() => { + setFullName(firstName + " " + middleName + " " + lastName); + }, [firstName, middleName, lastName]); + + return ( +
+ setLastName(e.target.value)} /> +
{fullName}
+
+ ); } export const FIXTURE_ENTRYPOINT = { @@ -107,8 +64,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js index f25e20863d339..31b77d1481719 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-local-state-and-component-scope.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({firstName}) { diff --git a/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 b/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 index 6981482545009..960cf987d4eea 100644 --- a/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 +++ b/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 @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({initialName}) { @@ -29,48 +29,21 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(6); - const { initialName } = t0; +function Component({ initialName }) { const [name, setName] = useState(""); - let t1; - let t2; - if ($[0] !== initialName) { - t1 = () => { - setName(initialName); - }; - t2 = [initialName]; - $[0] = initialName; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = (e) => setName(e.target.value); - $[3] = t3; - } else { - t3 = $[3]; - } - let t4; - if ($[4] !== name) { - t4 = ( -
- -
- ); - $[4] = name; - $[5] = t4; - } else { - t4 = $[5]; - } - return t4; + + useEffect(() => { + setName(initialName); + }, [initialName]); + + return ( +
+ setName(e.target.value)} /> +
+ ); } export const FIXTURE_ENTRYPOINT = { @@ -83,7 +56,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-call-outside-effect-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-call-outside-effect-no-error.js index 6df5f2eed6f92..e454caf2ec815 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-call-outside-effect-no-error.js +++ b/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,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({initialName}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.expect.md index 48811aa5a9433..226a3938bd7d3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint" function Component({value}) { const [checked, setChecked] = useState(''); @@ -19,36 +19,16 @@ function Component({value}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint" -function Component(t0) { - const $ = _c(5); - const { value } = t0; +function Component({ value }) { const [checked, setChecked] = useState(""); - let t1; - let t2; - if ($[0] !== value) { - t1 = () => { - setChecked(value === "" ? [] : value.split(",")); - }; - t2 = [value]; - $[0] = value; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== checked) { - t3 =
{checked}
; - $[3] = checked; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + + useEffect(() => { + setChecked(value === "" ? [] : value.split(",")); + }, [value]); + + return
{checked}
; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js index afd198caa262e..1c020d3015d10 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-ternary.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp +// @validateNoDerivedComputationsInEffects_exp @outputMode:"lint" function Component({value}) { const [checked, setChecked] = useState(''); diff --git a/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 b/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 index b5100dc2a6334..de184ede63946 100644 --- a/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 +++ b/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 @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function MockComponent({onSet}) { @@ -28,50 +28,20 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function MockComponent(t0) { - const $ = _c(2); - const { onSet } = t0; - let t1; - if ($[0] !== onSet) { - t1 =
onSet("clicked")}>Mock Component
; - $[0] = onSet; - $[1] = t1; - } else { - t1 = $[1]; - } - return t1; +function MockComponent({ onSet }) { + return
onSet("clicked")}>Mock Component
; } -function Component(t0) { - const $ = _c(4); - const { propValue } = t0; - const [, setValue] = useState(null); - let t1; - let t2; - if ($[0] !== propValue) { - t1 = () => { - setValue(propValue); - }; - t2 = [propValue]; - $[0] = propValue; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = ; - $[3] = t3; - } else { - t3 = $[3]; - } - return t3; +function Component({ propValue }) { + const [value, setValue] = useState(null); + useEffect(() => { + setValue(propValue); + }, [propValue]); + + return ; } export const FIXTURE_ENTRYPOINT = { @@ -84,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-used-outside-effect-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-used-outside-effect-no-error.js index 43b5a8c52ada8..879d582c924d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-setter-used-outside-effect-no-error.js +++ b/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,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function MockComponent({onSet}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.expect.md index 0160fbbb4a712..fc4d86a3f2926 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({value}) { @@ -26,38 +26,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(5); - const { value } = t0; +function Component({ value }) { const [localValue, setLocalValue] = useState(""); - let t1; - let t2; - if ($[0] !== value) { - t1 = () => { - setLocalValue(value); - document.title = `Value: ${value}`; - }; - t2 = [value]; - $[0] = value; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== localValue) { - t3 =
{localValue}
; - $[3] = localValue; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + + useEffect(() => { + setLocalValue(value); + document.title = `Value: ${value}`; + }, [value]); + + return
{localValue}
; } export const FIXTURE_ENTRYPOINT = { @@ -70,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js index 5bb963daac320..b6cebdb408074 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-prop-with-side-effect.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({value}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.expect.md index e88d5833a9a1b..f11a4b26b5335 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState, useRef} from 'react'; export default function Component({test}) { @@ -27,39 +27,19 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState, useRef } from "react"; -export default function Component(t0) { - const $ = _c(5); - const { test } = t0; +export default function Component({ test }) { const [local, setLocal] = useState(""); const myRef = useRef(null); - let t1; - let t2; - if ($[0] !== test) { - t1 = () => { - setLocal(myRef.current + test); - }; - t2 = [test]; - $[0] = test; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== local) { - t3 = <>{local}; - $[3] = local; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + + useEffect(() => { + setLocal(myRef.current + test); + }, [test]); + + return <>{local}; } export const FIXTURE_ENTRYPOINT = { @@ -72,7 +52,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.js index 18ad2bdca19fd..9425aee24419f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/derived-state-from-ref-and-state-no-error.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState, useRef} from 'react'; export default function Component({test}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.expect.md index fdc7081f3758a..080aa8e04dcd0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue}) { @@ -30,48 +30,22 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(6); - const { propValue } = t0; +function Component({ propValue }) { const [value, setValue] = useState(null); - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t1 = function localFunction() { - console.log("local function"); - }; - $[0] = t1; - } else { - t1 = $[0]; - } - const localFunction = t1; - let t2; - let t3; - if ($[1] !== propValue) { - t2 = () => { - setValue(propValue); - localFunction(); - }; - t3 = [propValue]; - $[1] = propValue; - $[2] = t2; - $[3] = t3; - } else { - t2 = $[2]; - t3 = $[3]; - } - useEffect(t2, t3); - let t4; - if ($[4] !== value) { - t4 =
{value}
; - $[4] = value; - $[5] = t4; - } else { - t4 = $[5]; + + function localFunction() { + console.log("local function"); } - return t4; + + useEffect(() => { + setValue(propValue); + localFunction(); + }, [propValue]); + + return
{value}
; } export const FIXTURE_ENTRYPOINT = { @@ -84,8 +58,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js index a6442b36477f9..3eabb40feeb63 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-local-function-call.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.expect.md index 74391e86ad375..374877863dd3b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue, onChange}) { @@ -25,43 +25,17 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(7); - const { propValue, onChange } = t0; +function Component({ propValue, onChange }) { const [value, setValue] = useState(null); - let t1; - if ($[0] !== onChange || $[1] !== propValue) { - t1 = () => { - setValue(propValue); - onChange(); - }; - $[0] = onChange; - $[1] = propValue; - $[2] = t1; - } else { - t1 = $[2]; - } - let t2; - if ($[3] !== propValue) { - t2 = [propValue]; - $[3] = propValue; - $[4] = t2; - } else { - t2 = $[4]; - } - useEffect(t1, t2); - let t3; - if ($[5] !== value) { - t3 =
{value}
; - $[5] = value; - $[6] = t3; - } else { - t3 = $[6]; - } - return t3; + useEffect(() => { + setValue(propValue); + onChange(); + }, [propValue]); + + return
{value}
; } export const FIXTURE_ENTRYPOINT = { @@ -74,8 +48,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.js index f19e9518d6fa4..c9c9778ab844c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-contains-prop-function-call-no-error.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue, onChange}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.expect.md index 6a3593a3b27c3..1bd8fa23faa78 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component({prop}) { const [s, setS] = useState(0); @@ -18,36 +18,15 @@ function Component({prop}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly - -function Component(t0) { - const $ = _c(5); - const { prop } = t0; - const [, setS] = useState(0); - let t1; - let t2; - if ($[0] !== prop) { - t1 = () => { - setS(prop); - }; - t2 = [prop, setS]; - $[0] = prop; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== prop) { - t3 =
{prop}
; - $[3] = prop; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" + +function Component({ prop }) { + const [s, setS] = useState(0); + useEffect(() => { + setS(prop); + }, [prop, setS]); + + return
{prop}
; } ``` @@ -55,8 +34,8 @@ function Component(t0) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.js index 1df99a191dcfe..bf48efbbc1007 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-used-in-dep-array-still-errors.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component({prop}) { const [s, setS] = useState(0); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.expect.md index e84031591e07c..ac72a44148446 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; @@ -29,39 +29,26 @@ function Component(file: File) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(file) { - const $ = _c(5); +function Component(file: File) { const [imageUrl, setImageUrl] = useState(null); - let t0; - let t1; - if ($[0] !== file) { - t0 = () => { - const imageUrlPrepared = URL.createObjectURL(file); - setImageUrl(imageUrlPrepared); - return () => URL.revokeObjectURL(imageUrlPrepared); - }; - t1 = [file]; - $[0] = file; - $[1] = t0; - $[2] = t1; - } else { - t0 = $[1]; - t1 = $[2]; - } - useEffect(t0, t1); - let t2; - if ($[3] !== imageUrl) { - t2 = ; - $[3] = imageUrl; - $[4] = t2; - } else { - t2 = $[4]; - } - return t2; + + /* + * Cleaning up the variable or a source of the variable used to setState + * inside the effect communicates that we always need to clean up something + * which is a valid use case for useEffect. In which case we want to + * avoid an throwing + */ + useEffect(() => { + const imageUrlPrepared = URL.createObjectURL(file); + setImageUrl(imageUrlPrepared); + return () => URL.revokeObjectURL(imageUrlPrepared); + }, [file]); + + return ; } ``` @@ -69,7 +56,7 @@ function Component(file) { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.js index e419583cc6dd3..16e52562bd834 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-cleanup-function-depending-on-derived-computation-value.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md index e26643723d980..58328b2e9597b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue}) { @@ -25,38 +25,17 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -function Component(t0) { - const $ = _c(5); - const { propValue } = t0; +function Component({ propValue }) { const [value, setValue] = useState(null); - let t1; - let t2; - if ($[0] !== propValue) { - t1 = () => { - setValue(propValue); - globalCall(); - }; - t2 = [propValue]; - $[0] = propValue; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== value) { - t3 =
{value}
; - $[3] = value; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + useEffect(() => { + setValue(propValue); + globalCall(); + }, [propValue]); + + return
{value}
; } export const FIXTURE_ENTRYPOINT = { @@ -69,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.js index ae7622d4d0642..565e23bb0fe3d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/effect-with-global-function-call-no-error.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component({propValue}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.expect.md index f23f51d6cb8bb..7ba22f5186420 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint" function Component({setParentState, prop}) { useEffect(() => { @@ -17,40 +17,14 @@ function Component({setParentState, prop}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint" -function Component(t0) { - const $ = _c(7); - const { setParentState, prop } = t0; - let t1; - if ($[0] !== prop || $[1] !== setParentState) { - t1 = () => { - setParentState(prop); - }; - $[0] = prop; - $[1] = setParentState; - $[2] = t1; - } else { - t1 = $[2]; - } - let t2; - if ($[3] !== prop) { - t2 = [prop]; - $[3] = prop; - $[4] = t2; - } else { - t2 = $[4]; - } - useEffect(t1, t2); - let t3; - if ($[5] !== prop) { - t3 =
{prop}
; - $[5] = prop; - $[6] = t3; - } else { - t3 = $[6]; - } - return t3; +function Component({ setParentState, prop }) { + useEffect(() => { + setParentState(prop); + }, [prop]); + + return
{prop}
; } ``` @@ -58,7 +32,7 @@ function Component(t0) { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.js index 4075975b32549..1754209d83713 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/from-props-setstate-in-effect-no-error.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @enableTreatSetIdentifiersAsStateSetters @loggerTestOnly @outputMode:"lint" function Component({setParentState, prop}) { useEffect(() => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.expect.md index 4e0ff4e2394d1..c1b99a95ab894 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component() { const [foo, setFoo] = useState({}); @@ -40,66 +40,37 @@ function Component() { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component() { - const $ = _c(9); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = {}; - $[0] = t0; - } else { - t0 = $[0]; - } - const [foo, setFoo] = useState(t0); - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = new Set(); - $[1] = t1; - } else { - t1 = $[1]; - } - const [bar] = useState(t1); - let t2; - let t3; - if ($[2] !== bar || $[3] !== foo) { - t2 = () => { - let isChanged = false; - - const newData = foo.map((val) => { - bar.someMethod(val); - isChanged = true; - }); - - if (isChanged) { - setFoo(newData); - } - }; - - t3 = [foo, bar]; - $[2] = bar; - $[3] = foo; - $[4] = t2; - $[5] = t3; - } else { - t2 = $[4]; - t3 = $[5]; - } - useEffect(t2, t3); - let t4; - if ($[6] !== bar || $[7] !== foo) { - t4 = ( -
- {foo}, {bar} -
- ); - $[6] = bar; - $[7] = foo; - $[8] = t4; - } else { - t4 = $[8]; - } - return t4; + const [foo, setFoo] = useState({}); + const [bar, setBar] = useState(new Set()); + + /* + * isChanged is considered context of the effect's function expression, + * if we don't bail out of effect mutation derivation tracking, isChanged + * will inherit the sources of the effect's function expression. + * + * This is innacurate and with the multiple passes ends up causing an infinite loop. + */ + useEffect(() => { + let isChanged = false; + + const newData = foo.map((val) => { + bar.someMethod(val); + isChanged = true; + }); + + if (isChanged) { + setFoo(newData); + } + }, [foo, bar]); + + return ( +
+ {foo}, {bar} +
+ ); } ``` @@ -107,8 +78,8 @@ function Component() { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.js index ab0bd70f363fc..856209928d1c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/function-expression-mutation-edge-case.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component() { const [foo, setFoo] = useState({}); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md index 29dea440b463d..928b7e9f71294 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { @@ -28,38 +28,20 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; function Component() { - const $ = _c(5); - const [firstName] = useState("Taylor"); + const [firstName, setFirstName] = useState("Taylor"); + const lastName = "Swift"; + // 🔴 Avoid: redundant state and unnecessary Effect const [fullName, setFullName] = useState(""); - let t0; - let t1; - if ($[0] !== firstName) { - t0 = () => { - setFullName(firstName + " " + "Swift"); - }; - t1 = [firstName, "Swift"]; - $[0] = firstName; - $[1] = t0; - $[2] = t1; - } else { - t0 = $[1]; - t1 = $[2]; - } - useEffect(t0, t1); - let t2; - if ($[3] !== fullName) { - t2 =
{fullName}
; - $[3] = fullName; - $[4] = t2; - } else { - t2 = $[4]; - } - return t2; + useEffect(() => { + setFullName(firstName + " " + lastName); + }, [firstName, lastName]); + + return
{fullName}
; } export const FIXTURE_ENTRYPOINT = { @@ -72,8 +54,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js index e29ece67bd57f..6cd45831215a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-computation-in-effect.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.expect.md index c7199d95480fe..c627b583b25b6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component(props) { @@ -26,39 +26,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; export default function Component(props) { - const $ = _c(7); const [displayValue, setDisplayValue] = useState(""); - let t0; - let t1; - if ($[0] !== props.prefix || $[1] !== props.suffix || $[2] !== props.value) { - t0 = () => { - const computed = props.prefix + props.value + props.suffix; - setDisplayValue(computed); - }; - t1 = [props.prefix, props.value, props.suffix]; - $[0] = props.prefix; - $[1] = props.suffix; - $[2] = props.value; - $[3] = t0; - $[4] = t1; - } else { - t0 = $[3]; - t1 = $[4]; - } - useEffect(t0, t1); - let t2; - if ($[5] !== displayValue) { - t2 =
{displayValue}
; - $[5] = displayValue; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; + + useEffect(() => { + const computed = props.prefix + props.value + props.suffix; + setDisplayValue(computed); + }, [props.prefix, props.value, props.suffix]); + + return
{displayValue}
; } export const FIXTURE_ENTRYPOINT = { @@ -71,8 +50,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js index 39648ef8d5eed..4243834c2f6c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-computed-props.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.expect.md index 5a6af555408e1..858daba502309 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component({props}) { @@ -27,40 +27,19 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState } from "react"; -export default function Component(t0) { - const $ = _c(6); - const { props } = t0; +export default function Component({ props }) { const [fullName, setFullName] = useState( props.firstName + " " + props.lastName, ); - let t1; - let t2; - if ($[0] !== props.firstName || $[1] !== props.lastName) { - t1 = () => { - setFullName(props.firstName + " " + props.lastName); - }; - t2 = [props.firstName, props.lastName]; - $[0] = props.firstName; - $[1] = props.lastName; - $[2] = t1; - $[3] = t2; - } else { - t1 = $[2]; - t2 = $[3]; - } - useEffect(t1, t2); - let t3; - if ($[4] !== fullName) { - t3 =
{fullName}
; - $[4] = fullName; - $[5] = t3; - } else { - t3 = $[5]; - } - return t3; + + useEffect(() => { + setFullName(props.firstName + " " + props.lastName); + }, [props.firstName, props.lastName]); + + return
{fullName}
; } export const FIXTURE_ENTRYPOINT = { @@ -73,8 +52,8 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js index 3f662f13f71cc..abb1643e69218 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/invalid-derived-state-from-destructured-props.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState} from 'react'; export default function Component({props}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.expect.md index 9a843d1883c31..70174794dc78f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState, useRef} from 'react'; export default function Component({test}) { @@ -31,44 +31,23 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import { useEffect, useState, useRef } from "react"; -export default function Component(t0) { - const $ = _c(5); - const { test } = t0; +export default function Component({ test }) { const [local, setLocal] = useState(0); const myRef = useRef(null); - let t1; - let t2; - if ($[0] !== test) { - t1 = () => { - if (myRef.current) { - setLocal(test); - } else { - setLocal(test + test); - } - }; - - t2 = [test]; - $[0] = test; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== local) { - t3 = <>{local}; - $[3] = local; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + + useEffect(() => { + if (myRef.current) { + setLocal(test); + } else { + setLocal(test + test); + } + }, [test]); + + return <>{local}; } export const FIXTURE_ENTRYPOINT = { @@ -81,7 +60,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.js index 3594deaa02e98..a5424ab03b2d6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/ref-conditional-in-effect-no-error.js @@ -1,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" import {useEffect, useState, useRef} from 'react'; export default function Component({test}) { diff --git a/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 b/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 index 87cf7722da353..690574e4429b1 100644 --- a/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 +++ b/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 @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component({prop}) { const [s, setS] = useState(); @@ -26,37 +26,23 @@ function Component({prop}) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" -function Component(t0) { - const $ = _c(5); - const { prop } = t0; +function Component({ prop }) { const [s, setS] = useState(); - const [second] = useState(prop); - let t1; - let t2; - if ($[0] !== second) { - t1 = () => { - setS(second); - }; - t2 = [second]; - $[0] = second; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); - let t3; - if ($[3] !== s) { - t3 =
{s}
; - $[3] = s; - $[4] = t3; - } else { - t3 = $[4]; - } - return t3; + const [second, setSecond] = useState(prop); + + /* + * `second` is a source of state. It will inherit the value of `prop` in + * the first render, but after that it will no longer be updated when + * `prop` changes. So we shouldn't consider `second` as being derived from + * `prop` + */ + useEffect(() => { + setS(second); + }, [second]); + + return
{s}
; } ``` @@ -64,8 +50,8 @@ function Component(t0) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/usestate-derived-from-prop-no-show-in-data-flow-tree.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/usestate-derived-from-prop-no-show-in-data-flow-tree.js index 5a7a693d50b01..3be4e88a07ad3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/usestate-derived-from-prop-no-show-in-data-flow-tree.js +++ b/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,4 +1,4 @@ -// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly +// @validateNoDerivedComputationsInEffects_exp @loggerTestOnly @outputMode:"lint" function Component({prop}) { const [s, setS] = useState(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md index d82575b8c354b..b5c079f5423b4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoJSXInTryStatements +// @validateNoJSXInTryStatements @outputMode:"lint" import {identity} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js index 9db091a2fb7ed..fbc0d292ce653 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js @@ -1,4 +1,4 @@ -// @validateNoJSXInTryStatements +// @validateNoJSXInTryStatements @outputMode:"lint" import {identity} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md index e8a29205647e6..79ae59e64c11a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoJSXInTryStatements +// @validateNoJSXInTryStatements @outputMode:"lint" function Component(props) { let el; try { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js index f0a17391c0eef..da1682772144d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js @@ -1,4 +1,4 @@ -// @validateNoJSXInTryStatements +// @validateNoJSXInTryStatements @outputMode:"lint" function Component(props) { let el; try { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md index 5eaa1fd5040bc..6ac06c1df23c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" import {identity} from 'shared-runtime'; function Component(props) { @@ -25,34 +25,17 @@ function Component(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" import { identity } from "shared-runtime"; function Component(props) { - const $ = _c(4); let el; try { let value; try { - let t0; - if ($[0] !== props.foo) { - t0 = identity(props.foo); - $[0] = props.foo; - $[1] = t0; - } else { - t0 = $[1]; - } - value = t0; + value = identity(props.foo); } catch { - let t0; - if ($[2] !== value) { - t0 =
; - $[2] = value; - $[3] = t0; - } else { - t0 = $[3]; - } - el = t0; + el =
; } } catch { return null; @@ -65,8 +48,8 @@ function Component(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.js index 3cf5cc9b8a600..a036272cdb05d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" import {identity} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md index 323aedd869de5..1e08cb24a6632 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" function Component(props) { let el; try { @@ -18,19 +18,11 @@ function Component(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" function Component(props) { - const $ = _c(1); let el; try { - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 =
; - $[0] = t0; - } else { - t0 = $[0]; - } - el = t0; + el =
; } catch { return null; } @@ -42,8 +34,8 @@ function Component(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.js index d01a93bf5afd5..45d932ec7c423 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateNoJSXInTryStatements +// @loggerTestOnly @validateNoJSXInTryStatements @outputMode:"lint" function Component(props) { let el; try { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md index 6e5762f3c883b..5cd44a9c851e2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { @@ -24,49 +24,30 @@ function Component() { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import { useEffect, useState } from "react"; function Component() { - const $ = _c(2); const [state, setState] = useState(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const f = () => { - setState(_temp); - }; - - t0 = () => { - f(); - }; - $[0] = t0; - } else { - t0 = $[0]; - } - const g = t0; - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = () => { - g(); - }; - $[1] = t1; - } else { - t1 = $[1]; - } - useEffect(t1); + const f = () => { + setState((s) => s + 1); + }; + const g = () => { + f(); + }; + useEffect(() => { + g(); + }); return state; } -function _temp(s) { - return s + 1; -} ``` ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.js index 50007c0bd13a4..ef69e4be4339c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md index 3c3a5a8053ad5..5022b55171887 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { @@ -18,35 +18,24 @@ function Component() { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import { useEffect, useState } from "react"; function Component() { - const $ = _c(1); const [state, setState] = useState(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - setState(_temp); - }; - $[0] = t0; - } else { - t0 = $[0]; - } - useEffect(t0); + useEffect(() => { + setState((s) => s + 1); + }); return state; } -function _temp(s) { - return s + 1; -} ``` ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.js index a95d3642cb8de..d2422caea0223 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateNoSetStateInEffects +// @loggerTestOnly @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md index b6895fc396d9f..6625f0153e8a0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { let Component; if (props.cond) { @@ -18,31 +18,15 @@ function Example(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { - const $ = _c(3); let Component; if (props.cond) { - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = createComponent(); - $[0] = t0; - } else { - t0 = $[0]; - } - Component = t0; + Component = createComponent(); } else { Component = DefaultComponent; } - let t0; - if ($[1] !== Component) { - t0 = ; - $[1] = Component; - $[2] = t0; - } else { - t0 = $[2]; - } - return t0; + return ; } ``` @@ -50,8 +34,8 @@ function Example(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.js index 6ff7ff321c337..1022cc9d57529 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { let Component; if (props.cond) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md index 3d9f1f76f96c8..c6441bc4cb1ef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = createComponent(); return ; @@ -13,18 +13,10 @@ function Example(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { - const $ = _c(1); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const Component = createComponent(); - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; - } - return t0; + const Component = createComponent(); + return ; } ``` @@ -32,8 +24,8 @@ function Example(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.js index 209cc83d65a24..8992b8bf7c757 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = createComponent(); return ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md index 2939a27a88182..0882c4a100378 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { function Component() { return
; @@ -15,21 +15,12 @@ function Example(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { - const $ = _c(1); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const Component = function Component() { - return
; - }; - - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; + function Component() { + return
; } - return t0; + return ; } ``` @@ -37,8 +28,8 @@ function Example(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.js index e48712dbf75c6..123fb043eb19f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { function Component() { return
; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md index 860490581b1da..707a0a9585021 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = props.foo.bar(); return ; @@ -13,27 +13,10 @@ function Example(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { - const $ = _c(4); - let t0; - if ($[0] !== props.foo) { - t0 = props.foo.bar(); - $[0] = props.foo; - $[1] = t0; - } else { - t0 = $[1]; - } - const Component = t0; - let t1; - if ($[2] !== Component) { - t1 = ; - $[2] = Component; - $[3] = t1; - } else { - t1 = $[3]; - } - return t1; + const Component = props.foo.bar(); + return ; } ``` @@ -41,8 +24,8 @@ function Example(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.js index 7f43ffacbd45a..7392c74adccb9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = props.foo.bar(); return ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md index 8dbcf0f108afa..2607ef63d8da6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = new ComponentFactory(); return ; @@ -13,18 +13,10 @@ function Example(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { - const $ = _c(1); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const Component = new ComponentFactory(); - t0 = ; - $[0] = t0; - } else { - t0 = $[0]; - } - return t0; + const Component = new ComponentFactory(); + return ; } ``` @@ -32,8 +24,8 @@ function Example(props) { ## Logs ``` -{"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} -{"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} +{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.js index a735e076d9983..4b4e3f7f02407 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.js @@ -1,4 +1,4 @@ -// @loggerTestOnly @validateStaticComponents +// @loggerTestOnly @validateStaticComponents @outputMode:"lint" function Example(props) { const Component = new ComponentFactory(); return ; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.expect.md index e60888bafc647..8e9d259fa7153 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Tooltip() { @@ -27,28 +27,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import { useState, useRef, useEffect } from "react"; function Tooltip() { - const $ = _c(2); const ref = useRef(null); const [tooltipHeight, setTooltipHeight] = useState(0); - let t0; - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - const { height } = ref.current.getBoundingClientRect(); - setTooltipHeight(height); - }; - t1 = []; - $[0] = t0; - $[1] = t1; - } else { - t0 = $[0]; - t1 = $[1]; - } - useEffect(t0, t1); + + useEffect(() => { + const { height } = ref.current.getBoundingClientRect(); + setTooltipHeight(height); + }, []); + return tooltipHeight; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.js index e27292c0a8a85..88201926788c0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-set-state-in-useEffect-from-ref.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Tooltip() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.expect.md index ee19358f3fb0e..845711d24be7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useLayoutEffect} from 'react'; function Component() { @@ -26,34 +26,17 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import { useState, useRef, useLayoutEffect } from "react"; function Component() { - const $ = _c(3); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { size: 5 }; - $[0] = t0; - } else { - t0 = $[0]; - } - const ref = useRef(t0); + const ref = useRef({ size: 5 }); const [computedSize, setComputedSize] = useState(0); - let t1; - let t2; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = () => { - setComputedSize(ref.current.size * 10); - }; - t2 = []; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useLayoutEffect(t1, t2); + + useLayoutEffect(() => { + setComputedSize(ref.current.size * 10); + }, []); + return computedSize; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.js index d312b139b7012..c6903f8933271 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-arithmetic.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useLayoutEffect} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.expect.md index a7c3714b18f87..269bda83ce96d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component() { @@ -27,34 +27,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import { useState, useRef, useEffect } from "react"; function Component() { - const $ = _c(3); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = [1, 2, 3, 4, 5]; - $[0] = t0; - } else { - t0 = $[0]; - } - const ref = useRef(t0); + const ref = useRef([1, 2, 3, 4, 5]); const [value, setValue] = useState(0); - let t1; - let t2; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = () => { - setValue(ref.current[2]); - }; - t2 = []; - $[1] = t1; - $[2] = t2; - } else { - t1 = $[1]; - t2 = $[2]; - } - useEffect(t1, t2); + + useEffect(() => { + const index = 2; + setValue(ref.current[index]); + }, []); + return value; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.js index 90459ac445cf1..a5cfd5c2b2bd9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-array-index.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.expect.md index 8a46686fcde25..ce186bcddf441 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component() { @@ -33,34 +33,24 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import { useState, useRef, useEffect } from "react"; function Component() { - const $ = _c(2); const ref = useRef(null); const [width, setWidth] = useState(0); - let t0; - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - const getBoundingRect = function getBoundingRect(ref_0) { - if (ref_0.current) { - return ref_0.current.getBoundingClientRect?.()?.width ?? 100; - } - return 100; - }; - - setWidth(getBoundingRect(ref)); - }; - t1 = []; - $[0] = t0; - $[1] = t1; - } else { - t0 = $[0]; - t1 = $[1]; - } - useEffect(t0, t1); + + useEffect(() => { + function getBoundingRect(ref_0) { + if (ref_0.current) { + return ref_0.current.getBoundingClientRect?.()?.width ?? 100; + } + return 100; + } + + setWidth(getBoundingRect(ref)); + }, []); + return width; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.js index e37b3f3ea2b4b..8b92e7c5fd0df 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-effect-from-ref-function-call.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.expect.md index 43a84784ea0bf..6570731d290e0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component({x, y}) { @@ -48,40 +48,26 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint" import { useState, useRef, useEffect } from "react"; -function Component(t0) { - const $ = _c(4); - const { x, y } = t0; +function Component({ x, y }) { const previousXRef = useRef(null); const previousYRef = useRef(null); const [data, setData] = useState(null); - let t1; - let t2; - if ($[0] !== x || $[1] !== y) { - t1 = () => { - const previousX = previousXRef.current; - previousXRef.current = x; - const previousY = previousYRef.current; - previousYRef.current = y; - if (!areEqual(x, previousX) || !areEqual(y, previousY)) { - const data_0 = load({ x, y }); - setData(data_0); - } - }; - - t2 = [x, y]; - $[0] = x; - $[1] = y; - $[2] = t1; - $[3] = t2; - } else { - t1 = $[2]; - t2 = $[3]; - } - useEffect(t1, t2); + + useEffect(() => { + const previousX = previousXRef.current; + previousXRef.current = x; + const previousY = previousYRef.current; + previousYRef.current = y; + if (!areEqual(x, previousX) || !areEqual(y, previousY)) { + const data_0 = load({ x, y }); + setData(data_0); + } + }, [x, y]); + return data; } @@ -108,7 +94,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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} +{"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} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.js index 46f11057d1181..4e884e1c65ded 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-controlled-by-ref-value.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @loggerTestOnly @compilationMode:"infer" @outputMode:"lint" import {useState, useRef, useEffect} from 'react'; function Component({x, y}) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.expect.md index ac55bd0469935..da69a338f8a67 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { @@ -26,26 +26,17 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import { useEffect, useState } from "react"; function Component() { - const $ = _c(1); const [state, setState] = useState(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - const f = () => { - setState(); - }; - - setTimeout(() => f(), 10); + useEffect(() => { + const f = () => { + setState(); }; - $[0] = t0; - } else { - t0 = $[0]; - } - useEffect(t0); + setTimeout(() => f(), 10); + }); return state; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.js index 525f3e97d1911..f5255fd4b5082 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener-transitive.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.expect.md index a7deed9afb09e..7a5718a171039 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { @@ -23,22 +23,14 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import { useEffect, useState } from "react"; function Component() { - const $ = _c(1); const [state, setState] = useState(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - setTimeout(setState, 10); - }; - $[0] = t0; - } else { - t0 = $[0]; - } - useEffect(t0); + useEffect(() => { + setTimeout(setState, 10); + }); return state; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.js index 723e4841f6d3a..68f5da981fc6d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useEffect-listener.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects +// @validateNoSetStateInEffects @outputMode:"lint" import {useEffect, useState} from 'react'; function Component() { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.expect.md index cacd46bfe42a6..9a926dc2231e4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useLayoutEffect} from 'react'; function Tooltip() { @@ -27,28 +27,18 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import { useState, useRef, useLayoutEffect } from "react"; function Tooltip() { - const $ = _c(2); const ref = useRef(null); const [tooltipHeight, setTooltipHeight] = useState(0); - let t0; - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - const { height } = ref.current.getBoundingClientRect(); - setTooltipHeight(height); - }; - t1 = []; - $[0] = t0; - $[1] = t1; - } else { - t0 = $[0]; - t1 = $[1]; - } - useLayoutEffect(t0, t1); + + useLayoutEffect(() => { + const { height } = ref.current.getBoundingClientRect(); + setTooltipHeight(height); + }, []); + return tooltipHeight; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.js index 339b550730d77..b41b2c1e7ce55 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/valid-setState-in-useLayoutEffect-from-ref.js @@ -1,4 +1,4 @@ -// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects +// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint" import {useState, useRef, useLayoutEffect} from 'react'; function Tooltip() {