Skip to content

Commit cce4aab

Browse files
committed
[Compiler] Don't throw calculate in render when there is a ref in the effect
1 parent 59d6bf9 commit cce4aab

7 files changed

+308
-0
lines changed

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

Lines changed: 19 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';
@@ -291,6 +292,11 @@ function validateEffect(
291292
}
292293

293294
for (const instr of block.instructions) {
295+
// Early return if any instruction is deriving a value from a ref
296+
if (isUseRefType(instr.lvalue.identifier)) {
297+
return;
298+
}
299+
294300
if (
295301
instr.value.kind === 'CallExpression' &&
296302
isSetStateType(instr.value.callee.identifier) &&
@@ -307,6 +313,19 @@ function validateEffect(
307313
sourceIds: argMetadata.sourcesIds,
308314
});
309315
}
316+
} else if (instr.value.kind === 'CallExpression') {
317+
const calleeMetadata = derivationCache.get(
318+
instr.value.callee.identifier.id,
319+
);
320+
321+
if (
322+
calleeMetadata !== undefined &&
323+
(calleeMetadata.typeOfValue === 'fromProps' ||
324+
calleeMetadata.typeOfValue === 'fromPropsAndState')
325+
) {
326+
// If the callee is a prop we can't confidently say that it should be derived in render
327+
return;
328+
}
310329
}
311330
}
312331
seenBlocks.add(block.id);
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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateNoDerivedComputationsInEffects
6+
import {useEffect, useState} from 'react';
7+
8+
function Component({propValue, onChange}) {
9+
const [value, setValue] = useState(null);
10+
useEffect(() => {
11+
setValue(propValue);
12+
onChange();
13+
}, [propValue]);
14+
15+
return <div>{value}</div>;
16+
}
17+
18+
export const FIXTURE_ENTRYPOINT = {
19+
fn: Component,
20+
params: [{propValue: 'test', onChange: () => {}}],
21+
};
22+
23+
```
24+
25+
## Code
26+
27+
```javascript
28+
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects
29+
import { useEffect, useState } from "react";
30+
31+
function Component(t0) {
32+
const $ = _c(7);
33+
const { propValue, onChange } = t0;
34+
const [value, setValue] = useState(null);
35+
let t1;
36+
if ($[0] !== onChange || $[1] !== propValue) {
37+
t1 = () => {
38+
setValue(propValue);
39+
onChange();
40+
};
41+
$[0] = onChange;
42+
$[1] = propValue;
43+
$[2] = t1;
44+
} else {
45+
t1 = $[2];
46+
}
47+
let t2;
48+
if ($[3] !== propValue) {
49+
t2 = [propValue];
50+
$[3] = propValue;
51+
$[4] = t2;
52+
} else {
53+
t2 = $[4];
54+
}
55+
useEffect(t1, t2);
56+
let t3;
57+
if ($[5] !== value) {
58+
t3 = <div>{value}</div>;
59+
$[5] = value;
60+
$[6] = t3;
61+
} else {
62+
t3 = $[6];
63+
}
64+
return t3;
65+
}
66+
67+
export const FIXTURE_ENTRYPOINT = {
68+
fn: Component,
69+
params: [{ propValue: "test", onChange: () => {} }],
70+
};
71+
72+
```
73+
74+
### Eval output
75+
(kind: ok) <div>test</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @validateNoDerivedComputationsInEffects
2+
import {useEffect, useState} from 'react';
3+
4+
function Component({propValue, onChange}) {
5+
const [value, setValue] = useState(null);
6+
useEffect(() => {
7+
setValue(propValue);
8+
onChange();
9+
}, [propValue]);
10+
11+
return <div>{value}</div>;
12+
}
13+
14+
export const FIXTURE_ENTRYPOINT = {
15+
fn: Component,
16+
params: [{propValue: 'test', onChange: () => {}}],
17+
};
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)