[compiler] Allow different dependencies from explicit memoization when dependency is a ref
Summary: In theory, as I understand it, the result of a useRef will never change between renders, because we'll always provide the same ref value consistently. That means that memoization that depends on a ref value will never re-compute, so I think we could not infer it as a dependency in Forget. This diff, however, doesn't do that: it instead allows the validatePreserveExistingMemoizationGuarantees analysis to admit mismatches between explicit dependencies and implicit ones when the implicit dependency is a ref that doesn't exist in source. ghstack-source-id: 685d859d1eed5d1e19dbbbfadc75be3875ddb6ea Pull Request resolved: https://github.com/facebook/react/pull/30679
Mike Vitousek committed
Aug 14, 2024 at 13:54 UTC
179197a22a0c00bc30c1a44275e7b4b1b2cec019
29 files changed
+306
-310
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+6
-1
@@ -1616,7 +1616,12 @@ export function isDispatcherType(id: Identifier): boolean {
1616
}
1617
1618
export function isStableType(id: Identifier): boolean {
1619
- return isSetStateType(id) || isSetActionStateType(id) || isDispatcherType(id);
1619
+ return (
1620
+ isSetStateType(id) ||
1621
+ isSetActionStateType(id) ||
1622
+ isDispatcherType(id) ||
1623
+ isUseRefType(id)
1624
+ );
1625
}
1626
1627
export function isUseEffectHookType(id: Identifier): boolean {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx-indirect.expect.md
+14
-39
@@ -40,62 +40,37 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
40
import { useRef } from "react";
41
42
function Component() {
43
- const $ = _c(10);
43
+ const $ = _c(2);
44
const ref = useRef(null);
45
let t0;
46
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
47
- t0 = () => {
47
+ const setRef = () => {
48
if (ref.current !== null) {
49
ref.current = "";
50
}
51
};
52
+
53
+ t0 = () => {
54
+ setRef();
55
+ };
56
$[0] = t0;
57
} else {
58
t0 = $[0];
59
}
56
- const setRef = t0;
60
+ const onClick = t0;
61
let t1;
58
- if ($[1] !== setRef) {
59
- t1 = () => {
60
- setRef();
61
- };
62
- $[1] = setRef;
63
- $[2] = t1;
64
- } else {
65
- t1 = $[2];
66
- }
67
- const onClick = t1;
68
- let t2;
69
- if ($[3] !== ref) {
70
- t2 = <input ref={ref} />;
71
- $[3] = ref;
72
- $[4] = t2;
73
- } else {
74
- t2 = $[4];
75
- }
76
- let t3;
77
- if ($[5] !== onClick) {
78
- t3 = <button onClick={onClick} />;
79
- $[5] = onClick;
80
- $[6] = t3;
81
- } else {
82
- t3 = $[6];
83
- }
84
- let t4;
85
- if ($[7] !== t2 || $[8] !== t3) {
86
- t4 = (
62
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
63
+ t1 = (
64
<>
88
- {t2}
89
- {t3}
65
+ <input ref={ref} />
66
+ <button onClick={onClick} />
67
</>
68
);
92
- $[7] = t2;
93
- $[8] = t3;
94
- $[9] = t4;
69
+ $[1] = t1;
70
} else {
96
- t4 = $[9];
71
+ t1 = $[1];
72
}
98
- return t4;
73
+ return t1;
74
}
75
76
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-in-callback-passed-to-jsx.expect.md
+8
-26
@@ -36,7 +36,7 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
36
import { useRef } from "react";
37
38
function Component() {
39
- const $ = _c(8);
39
+ const $ = _c(2);
40
const ref = useRef(null);
41
let t0;
42
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -51,36 +51,18 @@ function Component() {
51
}
52
const onClick = t0;
53
let t1;
54
- if ($[1] !== ref) {
55
- t1 = <input ref={ref} />;
56
- $[1] = ref;
57
- $[2] = t1;
58
- } else {
59
- t1 = $[2];
60
- }
61
- let t2;
62
- if ($[3] !== onClick) {
63
- t2 = <button onClick={onClick} />;
64
- $[3] = onClick;
65
- $[4] = t2;
66
- } else {
67
- t2 = $[4];
68
- }
69
- let t3;
70
- if ($[5] !== t1 || $[6] !== t2) {
71
- t3 = (
54
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
55
+ t1 = (
56
<>
73
- {t1}
74
- {t2}
57
+ <input ref={ref} />
58
+ <button onClick={onClick} />
59
</>
60
);
77
- $[5] = t1;
78
- $[6] = t2;
79
- $[7] = t3;
61
+ $[1] = t1;
62
} else {
81
- t3 = $[7];
63
+ t1 = $[1];
64
}
83
- return t3;
65
+ return t1;
66
}
67
68
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx-indirect.expect.md
+14
-39
@@ -40,62 +40,37 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
40
import { useRef } from "react";
41
42
function Component() {
43
- const $ = _c(10);
43
+ const $ = _c(2);
44
const ref = useRef(null);
45
let t0;
46
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
47
- t0 = () => {
47
+ const setRef = () => {
48
if (ref.current !== null) {
49
ref.current.value = "";
50
}
51
};
52
+
53
+ t0 = () => {
54
+ setRef();
55
+ };
56
$[0] = t0;
57
} else {
58
t0 = $[0];
59
}
56
- const setRef = t0;
60
+ const onClick = t0;
61
let t1;
58
- if ($[1] !== setRef) {
59
- t1 = () => {
60
- setRef();
61
- };
62
- $[1] = setRef;
63
- $[2] = t1;
64
- } else {
65
- t1 = $[2];
66
- }
67
- const onClick = t1;
68
- let t2;
69
- if ($[3] !== ref) {
70
- t2 = <input ref={ref} />;
71
- $[3] = ref;
72
- $[4] = t2;
73
- } else {
74
- t2 = $[4];
75
- }
76
- let t3;
77
- if ($[5] !== onClick) {
78
- t3 = <button onClick={onClick} />;
79
- $[5] = onClick;
80
- $[6] = t3;
81
- } else {
82
- t3 = $[6];
83
- }
84
- let t4;
85
- if ($[7] !== t2 || $[8] !== t3) {
86
- t4 = (
62
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
63
+ t1 = (
64
<>
88
- {t2}
89
- {t3}
65
+ <input ref={ref} />
66
+ <button onClick={onClick} />
67
</>
68
);
92
- $[7] = t2;
93
- $[8] = t3;
94
- $[9] = t4;
69
+ $[1] = t1;
70
} else {
96
- t4 = $[9];
71
+ t1 = $[1];
72
}
98
- return t4;
73
+ return t1;
74
}
75
76
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutating-ref-property-in-callback-passed-to-jsx.expect.md
+8
-26
@@ -36,7 +36,7 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
36
import { useRef } from "react";
37
38
function Component() {
39
- const $ = _c(8);
39
+ const $ = _c(2);
40
const ref = useRef(null);
41
let t0;
42
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -51,36 +51,18 @@ function Component() {
51
}
52
const onClick = t0;
53
let t1;
54
- if ($[1] !== ref) {
55
- t1 = <input ref={ref} />;
56
- $[1] = ref;
57
- $[2] = t1;
58
- } else {
59
- t1 = $[2];
60
- }
61
- let t2;
62
- if ($[3] !== onClick) {
63
- t2 = <button onClick={onClick} />;
64
- $[3] = onClick;
65
- $[4] = t2;
66
- } else {
67
- t2 = $[4];
68
- }
69
- let t3;
70
- if ($[5] !== t1 || $[6] !== t2) {
71
- t3 = (
54
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
55
+ t1 = (
56
<>
73
- {t1}
74
- {t2}
57
+ <input ref={ref} />
58
+ <button onClick={onClick} />
59
</>
60
);
77
- $[5] = t1;
78
- $[6] = t2;
79
- $[7] = t3;
61
+ $[1] = t1;
62
} else {
81
- t3 = $[7];
63
+ t1 = $[1];
64
}
83
- return t3;
65
+ return t1;
66
}
67
68
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-passing-refs-as-props.expect.md
+4
-5
@@ -14,15 +14,14 @@ function Component(props) {
14
```javascript
15
import { c as _c } from "react/compiler-runtime";
16
function Component(props) {
17
- const $ = _c(2);
17
+ const $ = _c(1);
18
const ref = useRef(null);
19
let t0;
20
- if ($[0] !== ref) {
20
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21
t0 = <Foo ref={ref} />;
22
- $[0] = ref;
23
- $[1] = t0;
22
+ $[0] = t0;
23
} else {
25
- t0 = $[1];
24
+ t0 = $[0];
25
}
26
return t0;
27
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-effect-indirect.expect.md
+16
-21
@@ -46,7 +46,7 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
46
import { useCallback, useEffect, useRef, useState } from "react";
47
48
function Component() {
49
- const $ = _c(9);
49
+ const $ = _c(7);
50
const ref = useRef(null);
51
const [state, setState] = useState(false);
52
let t0;
@@ -60,47 +60,42 @@ function Component() {
60
}
61
const setRef = t0;
62
let t1;
63
- if ($[1] !== setRef) {
63
+ let t2;
64
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
65
t1 = () => {
66
setRef();
67
};
67
- $[1] = setRef;
68
- $[2] = t1;
69
- } else {
70
- t1 = $[2];
71
- }
72
- let t2;
73
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
68
t2 = [];
75
- $[3] = t2;
69
+ $[1] = t1;
70
+ $[2] = t2;
71
} else {
77
- t2 = $[3];
72
+ t1 = $[1];
73
+ t2 = $[2];
74
}
75
useEffect(t1, t2);
76
let t3;
77
let t4;
82
- if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
78
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
79
t3 = () => {
80
setState(true);
81
};
82
t4 = [];
87
- $[4] = t3;
88
- $[5] = t4;
83
+ $[3] = t3;
84
+ $[4] = t4;
85
} else {
90
- t3 = $[4];
91
- t4 = $[5];
86
+ t3 = $[3];
87
+ t4 = $[4];
88
}
89
useEffect(t3, t4);
90
91
const t5 = String(state);
92
let t6;
97
- if ($[6] !== t5 || $[7] !== ref) {
93
+ if ($[5] !== t5) {
94
t6 = <Child key={t5} ref={ref} />;
99
- $[6] = t5;
100
- $[7] = ref;
101
- $[8] = t6;
95
+ $[5] = t5;
96
+ $[6] = t6;
97
} else {
103
- t6 = $[8];
98
+ t6 = $[6];
99
}
100
return t6;
101
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-effect.expect.md
+4
-5
@@ -42,7 +42,7 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
42
import { useEffect, useRef, useState } from "react";
43
44
function Component() {
45
- const $ = _c(7);
45
+ const $ = _c(6);
46
const ref = useRef(null);
47
const [state, setState] = useState(false);
48
let t0;
@@ -76,13 +76,12 @@ function Component() {
76
77
const t4 = String(state);
78
let t5;
79
- if ($[4] !== t4 || $[5] !== ref) {
79
+ if ($[4] !== t4) {
80
t5 = <Child key={t4} ref={ref} />;
81
$[4] = t4;
82
- $[5] = ref;
83
- $[6] = t5;
82
+ $[5] = t5;
83
} else {
85
- t5 = $[6];
84
+ t5 = $[5];
85
}
86
return t5;
87
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-unused-callback-nested.expect.md
+4
-5
@@ -44,7 +44,7 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen
44
import { useEffect, useRef, useState } from "react";
45
46
function Component() {
47
- const $ = _c(7);
47
+ const $ = _c(6);
48
const ref = useRef(null);
49
const [state, setState] = useState(false);
50
let t0;
@@ -77,13 +77,12 @@ function Component() {
77
78
const t4 = String(state);
79
let t5;
80
- if ($[4] !== t4 || $[5] !== ref) {
80
+ if ($[4] !== t4) {
81
t5 = <Child key={t4} ref={ref} />;
82
$[4] = t4;
83
- $[5] = ref;
84
- $[6] = t5;
83
+ $[5] = t5;
84
} else {
86
- t5 = $[6];
85
+ t5 = $[5];
86
}
87
return t5;
88
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md
+21
-24
@@ -37,45 +37,42 @@ import { useRef } from "react";
37
import { addOne } from "shared-runtime";
38
39
function useKeyCommand() {
40
- const $ = _c(7);
40
+ const $ = _c(6);
41
const currentPosition = useRef(0);
42
const handleKey = (direction) => () => {
43
const position = currentPosition.current;
44
const nextPosition = direction === "left" ? addOne(position) : position;
45
currentPosition.current = nextPosition;
46
};
47
-
48
- const t0 = handleKey("left");
49
- let t1;
50
- if ($[0] !== t0) {
51
- t1 = { handler: t0 };
47
+ let t0;
48
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
49
+ t0 = { handler: handleKey("left") };
50
$[0] = t0;
53
- $[1] = t1;
51
} else {
55
- t1 = $[1];
52
+ t0 = $[0];
53
}
57
- const moveLeft = t1;
54
+ const moveLeft = t0;
55
59
- const t2 = handleKey("right");
60
- let t3;
61
- if ($[2] !== t2) {
62
- t3 = { handler: t2 };
56
+ const t1 = handleKey("right");
57
+ let t2;
58
+ if ($[1] !== t1) {
59
+ t2 = { handler: t1 };
60
+ $[1] = t1;
61
$[2] = t2;
64
- $[3] = t3;
62
} else {
66
- t3 = $[3];
63
+ t2 = $[2];
64
}
68
- const moveRight = t3;
69
- let t4;
70
- if ($[4] !== moveLeft || $[5] !== moveRight) {
71
- t4 = [moveLeft, moveRight];
72
- $[4] = moveLeft;
73
- $[5] = moveRight;
74
- $[6] = t4;
65
+ const moveRight = t2;
66
+ let t3;
67
+ if ($[3] !== moveLeft || $[4] !== moveRight) {
68
+ t3 = [moveLeft, moveRight];
69
+ $[3] = moveLeft;
70
+ $[4] = moveRight;
71
+ $[5] = t3;
72
} else {
76
- t4 = $[6];
73
+ t3 = $[5];
74
}
78
- return t4;
75
+ return t3;
76
}
77
78
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md
new
+48
@@ -0,0 +1,48 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validatePreserveExistingMemoizationGuarantees
6
+import {useCallback, useRef} from 'react';
7
+
8
+function useFoo({cond}) {
9
+ const ref1 = useRef<undefined | (() => undefined)>();
10
+ const ref2 = useRef<undefined | (() => undefined)>();
11
+ const ref = cond ? ref1 : ref2;
12
+
13
+ return useCallback(() => {
14
+ if (ref != null) {
15
+ ref.current();
16
+ }
17
+ }, []);
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: useFoo,
22
+ params: [],
23
+};
24
+
25
+```
26
+
27
+
28
+## Error
29
+
30
+```
31
+ 7 | const ref = cond ? ref1 : ref2;
32
+ 8 |
33
+> 9 | return useCallback(() => {
34
+ | ^^^^^^^
35
+> 10 | if (ref != null) {
36
+ | ^^^^^^^^^^^^^^^^^^^^^^
37
+> 11 | ref.current();
38
+ | ^^^^^^^^^^^^^^^^^^^^^^
39
+> 12 | }
40
+ | ^^^^^^^^^^^^^^^^^^^^^^
41
+> 13 | }, []);
42
+ | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (9:13)
43
+ 14 | }
44
+ 15 |
45
+ 16 | export const FIXTURE_ENTRYPOINT = {
46
+```
47
+
48
+
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.ts
new
+19
@@ -0,0 +1,19 @@
1
+// @validatePreserveExistingMemoizationGuarantees
2
+import {useCallback, useRef} from 'react';
3
+
4
+function useFoo({cond}) {
5
+ const ref1 = useRef<undefined | (() => undefined)>();
6
+ const ref2 = useRef<undefined | (() => undefined)>();
7
+ const ref = cond ? ref1 : ref2;
8
+
9
+ return useCallback(() => {
10
+ if (ref != null) {
11
+ ref.current();
12
+ }
13
+ }, []);
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: useFoo,
18
+ params: [],
19
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-ref-missing-ok.expect.md
new
+56
@@ -0,0 +1,56 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validatePreserveExistingMemoizationGuarantees
6
+import {useCallback, useRef} from 'react';
7
+
8
+function useFoo() {
9
+ const ref = useRef<undefined | (() => undefined)>();
10
+
11
+ return useCallback(() => {
12
+ if (ref != null) {
13
+ ref.current();
14
+ }
15
+ }, []);
16
+}
17
+
18
+export const FIXTURE_ENTRYPOINT = {
19
+ fn: useFoo,
20
+ params: [],
21
+};
22
+
23
+```
24
+
25
+## Code
26
+
27
+```javascript
28
+import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
29
+import { useCallback, useRef } from "react";
30
+
31
+function useFoo() {
32
+ const $ = _c(1);
33
+ const ref = useRef();
34
+ let t0;
35
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
36
+ t0 = () => {
37
+ if (ref != null) {
38
+ ref.current();
39
+ }
40
+ };
41
+ $[0] = t0;
42
+ } else {
43
+ t0 = $[0];
44
+ }
45
+ return t0;
46
+}
47
+
48
+export const FIXTURE_ENTRYPOINT = {
49
+ fn: useFoo,
50
+ params: [],
51
+};
52
+
53
+```
54
+
55
+### Eval output
56
+(kind: ok) "[[ function params=0 ]]"
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-ref-missing-ok.ts
new
+17
@@ -0,0 +1,17 @@
1
+// @validatePreserveExistingMemoizationGuarantees
2
+import {useCallback, useRef} from 'react';
3
+
4
+function useFoo() {
5
+ const ref = useRef<undefined | (() => undefined)>();
6
+
7
+ return useCallback(() => {
8
+ if (ref != null) {
9
+ ref.current();
10
+ }
11
+ }, []);
12
+}
13
+
14
+export const FIXTURE_ENTRYPOINT = {
15
+ fn: useFoo,
16
+ params: [],
17
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/react-namespace.expect.md
+5
-6
@@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime";
29
const FooContext = React.createContext({ current: null });
30
31
function Component(props) {
32
- const $ = _c(6);
32
+ const $ = _c(5);
33
React.useContext(FooContext);
34
const ref = React.useRef();
35
const [x, setX] = React.useState(false);
@@ -53,13 +53,12 @@ function Component(props) {
53
t1 = $[2];
54
}
55
let t2;
56
- if ($[3] !== onClick || $[4] !== t1) {
56
+ if ($[3] !== t1) {
57
t2 = <div onClick={onClick}>{t1}</div>;
58
- $[3] = onClick;
59
- $[4] = t1;
60
- $[5] = t2;
58
+ $[3] = t1;
59
+ $[4] = t2;
60
} else {
62
- t2 = $[5];
61
+ t2 = $[4];
62
}
63
return t2;
64
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-aliased-no-added-to-dep.expect.md
+5
-12
@@ -20,28 +20,21 @@ function VideoTab() {
20
```javascript
21
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender false
22
function VideoTab() {
23
- const $ = _c(3);
23
+ const $ = _c(1);
24
const ref = useRef();
25
const t = ref.current;
26
let t0;
27
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28
- t0 = () => {
28
+ const x = () => {
29
console.log(t);
30
};
31
+
32
+ t0 = <VideoList videos={x} />;
33
$[0] = t0;
34
} else {
35
t0 = $[0];
36
}
35
- const x = t0;
36
- let t1;
37
- if ($[1] !== x) {
38
- t1 = <VideoList videos={x} />;
39
- $[1] = x;
40
- $[2] = t1;
41
- } else {
42
- t1 = $[2];
43
- }
44
- return t1;
37
+ return t0;
38
}
39
40
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-field-not-added-to-dep.expect.md
+5
-12
@@ -19,27 +19,20 @@ function VideoTab() {
19
```javascript
20
import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRender false
21
function VideoTab() {
22
- const $ = _c(3);
22
+ const $ = _c(1);
23
const ref = useRef();
24
let t0;
25
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
26
- t0 = () => {
26
+ const x = () => {
27
console.log(ref.current.x);
28
};
29
+
30
+ t0 = <VideoList videos={x} />;
31
$[0] = t0;
32
} else {
33
t0 = $[0];
34
}
33
- const x = t0;
34
- let t1;
35
- if ($[1] !== x) {
36
- t1 = <VideoList videos={x} />;
37
- $[1] = x;
38
- $[2] = t1;
39
- } else {
40
- t1 = $[2];
41
- }
42
- return t1;
35
+ return t0;
36
}
37
38
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-field-write-not-added-to-dep.expect.md
+5
-12
@@ -27,7 +27,7 @@ import { c as _c } from "react/compiler-runtime";
27
import { useRef } from "react";
28
29
function Component() {
30
- const $ = _c(4);
30
+ const $ = _c(2);
31
let t0;
32
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33
t0 = { text: { value: null } };
@@ -38,23 +38,16 @@ function Component() {
38
const ref = useRef(t0);
39
let t1;
40
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
41
- t1 = (e) => {
41
+ const inputChanged = (e) => {
42
ref.current.text.value = e.target.value;
43
};
44
+
45
+ t1 = <input onChange={inputChanged} />;
46
$[1] = t1;
47
} else {
48
t1 = $[1];
49
}
48
- const inputChanged = t1;
49
- let t2;
50
- if ($[2] !== inputChanged) {
51
- t2 = <input onChange={inputChanged} />;
52
- $[2] = inputChanged;
53
- $[3] = t2;
54
- } else {
55
- t2 = $[3];
56
- }
57
- return t2;
50
+ return t1;
51
}
52
53
export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-not-added-to-dep.expect.md
+5
-12
@@ -18,27 +18,20 @@ function VideoTab() {
18
```javascript
19
import { c as _c } from "react/compiler-runtime";
20
function VideoTab() {
21
- const $ = _c(3);
21
+ const $ = _c(1);
22
const ref = useRef();
23
let t0;
24
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
- t0 = () => {
25
+ const x = () => {
26
console.log(ref.current);
27
};
28
+
29
+ t0 = <VideoList videos={x} />;
30
$[0] = t0;
31
} else {
32
t0 = $[0];
33
}
32
- const x = t0;
33
- let t1;
34
- if ($[1] !== x) {
35
- t1 = <VideoList videos={x} />;
36
- $[1] = x;
37
- $[2] = t1;
38
- } else {
39
- t1 = $[2];
40
- }
41
- return t1;
34
+ return t0;
35
}
36
37
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-optional-field-no-added-to-dep.expect.md
+5
-12
@@ -18,27 +18,20 @@ function VideoTab() {
18
```javascript
19
import { c as _c } from "react/compiler-runtime";
20
function VideoTab() {
21
- const $ = _c(3);
21
+ const $ = _c(1);
22
const ref = useRef();
23
let t0;
24
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
- t0 = () => {
25
+ const x = () => {
26
ref.current?.x;
27
};
28
+
29
+ t0 = <VideoList videos={x} />;
30
$[0] = t0;
31
} else {
32
t0 = $[0];
33
}
32
- const x = t0;
33
- let t1;
34
- if ($[1] !== x) {
35
- t1 = <VideoList videos={x} />;
36
- $[1] = x;
37
- $[2] = t1;
38
- } else {
39
- t1 = $[2];
40
- }
41
- return t1;
34
+ return t0;
35
}
36
37
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-current-write-not-added-to-dep.expect.md
+5
-12
@@ -18,27 +18,20 @@ function VideoTab() {
18
```javascript
19
import { c as _c } from "react/compiler-runtime";
20
function VideoTab() {
21
- const $ = _c(3);
21
+ const $ = _c(1);
22
const ref = useRef();
23
let t0;
24
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
- t0 = () => {
25
+ const x = () => {
26
ref.current = 1;
27
};
28
+
29
+ t0 = <VideoList videos={x} />;
30
$[0] = t0;
31
} else {
32
t0 = $[0];
33
}
32
- const x = t0;
33
- let t1;
34
- if ($[1] !== x) {
35
- t1 = <VideoList videos={x} />;
36
- $[1] = x;
37
- $[2] = t1;
38
- } else {
39
- t1 = $[2];
40
- }
41
- return t1;
34
+ return t0;
35
}
36
37
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-in-effect.expect.md
+4
-5
@@ -21,7 +21,7 @@ function Component(props) {
21
```javascript
22
import { c as _c } from "react/compiler-runtime";
23
function Component(props) {
24
- const $ = _c(4);
24
+ const $ = _c(3);
25
const ref = useRef(null);
26
let t0;
27
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -45,12 +45,11 @@ function Component(props) {
45
}
46
useEffect(t1);
47
let t2;
48
- if ($[2] !== onChange) {
48
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
49
t2 = <Foo onChange={onChange} />;
50
- $[2] = onChange;
51
- $[3] = t2;
50
+ $[2] = t2;
51
} else {
53
- t2 = $[3];
52
+ t2 = $[2];
53
}
54
return t2;
55
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback-2.expect.md
+4
-5
@@ -47,7 +47,7 @@ function useCustomRef() {
47
function _temp() {}
48
49
function Foo() {
50
- const $ = _c(3);
50
+ const $ = _c(2);
51
const ref = useCustomRef();
52
let t0;
53
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -60,12 +60,11 @@ function Foo() {
60
}
61
const onClick = t0;
62
let t1;
63
- if ($[1] !== onClick) {
63
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
64
t1 = <button onClick={onClick} />;
65
- $[1] = onClick;
66
- $[2] = t1;
65
+ $[1] = t1;
66
} else {
68
- t1 = $[2];
67
+ t1 = $[1];
68
}
69
return t1;
70
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ref-like-name-in-useCallback.expect.md
+4
-5
@@ -47,7 +47,7 @@ function useCustomRef() {
47
function _temp() {}
48
49
function Foo() {
50
- const $ = _c(3);
50
+ const $ = _c(2);
51
const customRef = useCustomRef();
52
let t0;
53
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -60,12 +60,11 @@ function Foo() {
60
}
61
const onClick = t0;
62
let t1;
63
- if ($[1] !== onClick) {
63
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
64
t1 = <button onClick={onClick} />;
65
- $[1] = onClick;
66
- $[2] = t1;
65
+ $[1] = t1;
66
} else {
68
- t1 = $[2];
67
+ t1 = $[1];
68
}
69
return t1;
70
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-multiple-callbacks-modifying-same-ref-preserve-memoization.expect.md
+4
-6
@@ -35,7 +35,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemo
35
import { useCallback, useRef } from "react";
36
37
function Component(props) {
38
- const $ = _c(6);
38
+ const $ = _c(4);
39
let t0;
40
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
41
t0 = { inner: null };
@@ -65,13 +65,11 @@ function Component(props) {
65
}
66
const onReset = t2;
67
let t3;
68
- if ($[3] !== onChange || $[4] !== onReset) {
68
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
69
t3 = <input onChange={onChange} onReset={onReset} />;
70
- $[3] = onChange;
71
- $[4] = onReset;
72
- $[5] = t3;
70
+ $[3] = t3;
71
} else {
74
- t3 = $[5];
72
+ t3 = $[3];
73
}
74
return t3;
75
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-preserve-memoization.expect.md
+4
-5
@@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemo
31
import { useCallback, useRef } from "react";
32
33
function Component(props) {
34
- const $ = _c(4);
34
+ const $ = _c(3);
35
let t0;
36
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
37
t0 = { inner: null };
@@ -51,12 +51,11 @@ function Component(props) {
51
}
52
const onChange = t1;
53
let t2;
54
- if ($[2] !== onChange) {
54
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
55
t2 = <input onChange={onChange} />;
56
- $[2] = onChange;
57
- $[3] = t2;
56
+ $[2] = t2;
57
} else {
59
- t2 = $[3];
58
+ t2 = $[2];
59
}
60
return t2;
61
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property.expect.md
+4
-5
@@ -34,7 +34,7 @@ import { useCallback, useRef } from "react";
34
// Identical to useCallback-set-ref-nested-property-preserve-memoization,
35
// but with a different set of compiler flags
36
function Component(t0) {
37
- const $ = _c(4);
37
+ const $ = _c(3);
38
let t1;
39
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
40
t1 = { inner: null };
@@ -54,12 +54,11 @@ function Component(t0) {
54
}
55
const onChange = t2;
56
let t3;
57
- if ($[2] !== onChange) {
57
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
58
t3 = <input onChange={onChange} />;
59
- $[2] = onChange;
60
- $[3] = t3;
59
+ $[2] = t3;
60
} else {
62
- t3 = $[3];
61
+ t3 = $[2];
62
}
63
return t3;
64
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-value-dont-preserve-memoization.expect.md
+4
-5
@@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemo
31
import { useCallback, useRef } from "react";
32
33
function Component(props) {
34
- const $ = _c(3);
34
+ const $ = _c(2);
35
const ref = useRef(null);
36
let t0;
37
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -44,12 +44,11 @@ function Component(props) {
44
}
45
const onChange = t0;
46
let t1;
47
- if ($[1] !== onChange) {
47
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
48
t1 = <input onChange={onChange} />;
49
- $[1] = onChange;
50
- $[2] = t1;
49
+ $[1] = t1;
50
} else {
52
- t1 = $[2];
51
+ t1 = $[1];
52
}
53
return t1;
54
}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-value-preserve-memoization.expect.md
+4
-5
@@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemo
31
import { useCallback, useRef } from "react";
32
33
function Component(props) {
34
- const $ = _c(3);
34
+ const $ = _c(2);
35
const ref = useRef(null);
36
let t0;
37
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -44,12 +44,11 @@ function Component(props) {
44
}
45
const onChange = t0;
46
let t1;
47
- if ($[1] !== onChange) {
47
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
48
t1 = <input onChange={onChange} />;
49
- $[1] = onChange;
50
- $[2] = t1;
49
+ $[1] = t1;
50
} else {
52
- t1 = $[2];
51
+ t1 = $[1];
52
}
53
return t1;
54
}