[compiler] Prevent local state source variables from depending on other state (#35044)
Summary: When a local state is created sometimes it uses a `prop` or even other local state for its initial value. This value is only relevant on first render so we shouldn't consider it part of our data flow Test Plan: Added tests
Jorge Cabiedes committed
Nov 10, 2025 at 12:29 UTC
100fc4a8cf3b97de53b3566ed726b8ea7e6d7f81
3 files changed
+85
-2
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects_exp.ts
+8
-2
@@ -358,8 +358,14 @@ function recordInstructionDerivations(
358
context.effects.add(effectFunction.loweredFunc.func);
359
}
360
} else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
361
- isSource = true;
362
- typeOfValue = joinValue(typeOfValue, 'fromState');
361
+ typeOfValue = 'fromState';
362
+ context.derivationCache.addDerivationEntry(
363
+ lvalue,
364
+ new Set(),
365
+ typeOfValue,
366
+ true,
367
+ );
368
+ return;
369
}
370
}
371
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
new
+59
@@ -0,0 +1,59 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validateNoDerivedComputationsInEffects_exp
6
+
7
+function Component({ prop }) {
8
+ const [s, setS] = useState(prop)
9
+ const [second, setSecond] = useState(prop)
10
+
11
+ useEffect(() => {
12
+ setS(second)
13
+ }, [second])
14
+
15
+ return <div>{s}</div>
16
+}
17
+
18
+```
19
+
20
+## Code
21
+
22
+```javascript
23
+import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
24
+
25
+function Component(t0) {
26
+ const $ = _c(5);
27
+ const { prop } = t0;
28
+ const [s, setS] = useState(prop);
29
+ const [second] = useState(prop);
30
+ let t1;
31
+ let t2;
32
+ if ($[0] !== second) {
33
+ t1 = () => {
34
+ setS(second);
35
+ };
36
+ t2 = [second];
37
+ $[0] = second;
38
+ $[1] = t1;
39
+ $[2] = t2;
40
+ } else {
41
+ t1 = $[1];
42
+ t2 = $[2];
43
+ }
44
+ useEffect(t1, t2);
45
+ let t3;
46
+ if ($[3] !== s) {
47
+ t3 = <div>{s}</div>;
48
+ $[3] = s;
49
+ $[4] = t3;
50
+ } else {
51
+ t3 = $[4];
52
+ }
53
+ return t3;
54
+}
55
+
56
+```
57
+
58
+### Eval output
59
+(kind: exception) Fixture not implemented
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/usestate-derived-from-prop-no-show-in-data-flow-tree.js
new
+18
@@ -0,0 +1,18 @@
1
+// @validateNoDerivedComputationsInEffects_exp
2
+
3
+function Component({prop}) {
4
+ const [s, setS] = useState();
5
+ const [second, setSecond] = useState(prop);
6
+
7
+ /*
8
+ * `second` is a source of state. It will inherit the value of `prop` in
9
+ * the first render, but after that it will no longer be updated when
10
+ * `prop` changes. So we shouldn't consider `second` as being derived from
11
+ * `prop`
12
+ */
13
+ useEffect(() => {
14
+ setS(second);
15
+ }, [second]);
16
+
17
+ return <div>{s}</div>;
18
+}