Skip to content

Commit 9d30c72

Browse files
committed
[compiler] Don't throw calculate in render when there is a ref in the effect
1 parent 8ec2b42 commit 9d30c72

File tree

5 files changed

+203
-0
lines changed

5 files changed

+203
-0
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
CallExpression,
1919
Instruction,
2020
isUseStateType,
21+
isUseRefType,
2122
} from '../HIR';
2223
import {eachInstructionLValue, eachInstructionOperand} from '../HIR/visitors';
2324
import {isMutable} from '../ReactiveScopes/InferReactiveScopeVariables';
@@ -284,6 +285,11 @@ function validateEffect(
284285
}
285286

286287
for (const instr of block.instructions) {
288+
// Early return if any instruction is deriving a value from a ref
289+
if (isUseRefType(instr.lvalue.identifier)) {
290+
return;
291+
}
292+
287293
if (
288294
instr.value.kind === 'CallExpression' &&
289295
isSetStateType(instr.value.callee.identifier) &&
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateNoDerivedComputationsInEffects
6+
import {useEffect, useState, useRef} from 'react';
7+
8+
export default function Component({test}) {
9+
const [local, setLocal] = useState('');
10+
11+
const myRef = useRef(null);
12+
13+
useEffect(() => {
14+
setLocal(myRef.current + test);
15+
}, [test]);
16+
17+
return <>{local}</>;
18+
}
19+
20+
export const FIXTURE_ENTRYPOINT = {
21+
fn: Component,
22+
params: [{test: 'testString'}],
23+
};
24+
25+
```
26+
27+
## Code
28+
29+
```javascript
30+
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects
31+
import { useEffect, useState, useRef } from "react";
32+
33+
export default function Component(t0) {
34+
const $ = _c(5);
35+
const { test } = t0;
36+
const [local, setLocal] = useState("");
37+
38+
const myRef = useRef(null);
39+
let t1;
40+
let t2;
41+
if ($[0] !== test) {
42+
t1 = () => {
43+
setLocal(myRef.current + test);
44+
};
45+
t2 = [test];
46+
$[0] = test;
47+
$[1] = t1;
48+
$[2] = t2;
49+
} else {
50+
t1 = $[1];
51+
t2 = $[2];
52+
}
53+
useEffect(t1, t2);
54+
let t3;
55+
if ($[3] !== local) {
56+
t3 = <>{local}</>;
57+
$[3] = local;
58+
$[4] = t3;
59+
} else {
60+
t3 = $[4];
61+
}
62+
return t3;
63+
}
64+
65+
export const FIXTURE_ENTRYPOINT = {
66+
fn: Component,
67+
params: [{ test: "testString" }],
68+
};
69+
70+
```
71+
72+
### Eval output
73+
(kind: ok) nulltestString
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @validateNoDerivedComputationsInEffects
2+
import {useEffect, useState, useRef} from 'react';
3+
4+
export default function Component({test}) {
5+
const [local, setLocal] = useState('');
6+
7+
const myRef = useRef(null);
8+
9+
useEffect(() => {
10+
setLocal(myRef.current + test);
11+
}, [test]);
12+
13+
return <>{local}</>;
14+
}
15+
16+
export const FIXTURE_ENTRYPOINT = {
17+
fn: Component,
18+
params: [{test: 'testString'}],
19+
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateNoDerivedComputationsInEffects
6+
import {useEffect, useState, useRef} from 'react';
7+
8+
export default function Component({test}) {
9+
const [local, setLocal] = useState(0);
10+
11+
const myRef = useRef(null);
12+
13+
useEffect(() => {
14+
if (myRef.current) {
15+
setLocal(test);
16+
} else {
17+
setLocal(test + test);
18+
}
19+
}, [test]);
20+
21+
return <>{local}</>;
22+
}
23+
24+
export const FIXTURE_ENTRYPOINT = {
25+
fn: Component,
26+
params: [{test: 4}],
27+
};
28+
29+
```
30+
31+
## Code
32+
33+
```javascript
34+
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects
35+
import { useEffect, useState, useRef } from "react";
36+
37+
export default function Component(t0) {
38+
const $ = _c(5);
39+
const { test } = t0;
40+
const [local, setLocal] = useState(0);
41+
42+
const myRef = useRef(null);
43+
let t1;
44+
let t2;
45+
if ($[0] !== test) {
46+
t1 = () => {
47+
if (myRef.current) {
48+
setLocal(test);
49+
} else {
50+
setLocal(test + test);
51+
}
52+
};
53+
54+
t2 = [test];
55+
$[0] = test;
56+
$[1] = t1;
57+
$[2] = t2;
58+
} else {
59+
t1 = $[1];
60+
t2 = $[2];
61+
}
62+
useEffect(t1, t2);
63+
let t3;
64+
if ($[3] !== local) {
65+
t3 = <>{local}</>;
66+
$[3] = local;
67+
$[4] = t3;
68+
} else {
69+
t3 = $[4];
70+
}
71+
return t3;
72+
}
73+
74+
export const FIXTURE_ENTRYPOINT = {
75+
fn: Component,
76+
params: [{ test: 4 }],
77+
};
78+
79+
```
80+
81+
### Eval output
82+
(kind: ok) 8
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @validateNoDerivedComputationsInEffects
2+
import {useEffect, useState, useRef} from 'react';
3+
4+
export default function Component({test}) {
5+
const [local, setLocal] = useState(0);
6+
7+
const myRef = useRef(null);
8+
9+
useEffect(() => {
10+
if (myRef.current) {
11+
setLocal(test);
12+
} else {
13+
setLocal(test + test);
14+
}
15+
}, [test]);
16+
17+
return <>{local}</>;
18+
}
19+
20+
export const FIXTURE_ENTRYPOINT = {
21+
fn: Component,
22+
params: [{test: 4}],
23+
};

0 commit comments

Comments
 (0)