Skip to content

Commit f305855

Browse files
committed
[Compiler] Don't throw calculate in render when there is a global function call in the effect
Summary: Global function calls can introduce unexpected side effects, for this first iteration we are bailing out the validation when we encounter one. Local function calls remain
1 parent f363996 commit f305855

File tree

4 files changed

+81
-43
lines changed

4 files changed

+81
-43
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ function validateEffect(
319319
sourceIds: Set<IdentifierId>;
320320
}> = [];
321321

322+
const globals: Set<IdentifierId> = new Set();
322323
for (const block of effectFunction.body.blocks.values()) {
323324
for (const pred of block.preds) {
324325
if (!seenBlocks.has(pred)) {
@@ -362,6 +363,16 @@ function validateEffect(
362363
// If the callee is a prop we can't confidently say that it should be derived in render
363364
return;
364365
}
366+
367+
if (globals.has(instr.value.callee.identifier.id)) {
368+
// If the callee is a global we can't confidently say that it should be derived in render
369+
return;
370+
}
371+
} else if (instr.value.kind === 'LoadGlobal') {
372+
globals.add(instr.lvalue.identifier.id);
373+
for (const operand of eachInstructionOperand(instr)) {
374+
globals.add(operand.identifier.id);
375+
}
365376
}
366377
}
367378
seenBlocks.add(block.id);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateNoDerivedComputationsInEffects
6+
import {useEffect, useState} from 'react';
7+
8+
function Component({propValue}) {
9+
const [value, setValue] = useState(null);
10+
useEffect(() => {
11+
setValue(propValue);
12+
globalCall();
13+
}, [propValue]);
14+
15+
return <div>{value}</div>;
16+
}
17+
18+
export const FIXTURE_ENTRYPOINT = {
19+
fn: Component,
20+
params: [{propValue: 'test'}],
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(5);
33+
const { propValue } = t0;
34+
const [value, setValue] = useState(null);
35+
let t1;
36+
let t2;
37+
if ($[0] !== propValue) {
38+
t1 = () => {
39+
setValue(propValue);
40+
globalCall();
41+
};
42+
t2 = [propValue];
43+
$[0] = propValue;
44+
$[1] = t1;
45+
$[2] = t2;
46+
} else {
47+
t1 = $[1];
48+
t2 = $[2];
49+
}
50+
useEffect(t1, t2);
51+
let t3;
52+
if ($[3] !== value) {
53+
t3 = <div>{value}</div>;
54+
$[3] = value;
55+
$[4] = t3;
56+
} else {
57+
t3 = $[4];
58+
}
59+
return t3;
60+
}
61+
62+
export const FIXTURE_ENTRYPOINT = {
63+
fn: Component,
64+
params: [{ propValue: "test" }],
65+
};
66+
67+
```
68+
69+
### Eval output
70+
(kind: exception) globalCall is not defined

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/effect-derived-computations/error.effect-with-global-function-call-no-error.expect.md

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)