Skip to content

Commit ed1e6f9

Browse files
committed
[compiler] Prevent local state source variables from depending on other state
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
1 parent 4f6b31a commit ed1e6f9

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects_exp.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,14 @@ function recordInstructionDerivations(
358358
context.effects.add(effectFunction.loweredFunc.func);
359359
}
360360
} 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;
363369
}
364370
}
365371

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)