Skip to content

Commit 0972e23

Browse files
authored
[compiler] Consider setter from useOptimistic non-reactive (facebook#35141)
Closes facebook#35138
1 parent 194c12d commit 0972e23

File tree

5 files changed

+176
-2
lines changed

5 files changed

+176
-2
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
BuiltInUseInsertionEffectHookId,
2424
BuiltInUseLayoutEffectHookId,
2525
BuiltInUseOperatorId,
26+
BuiltInUseOptimisticId,
2627
BuiltInUseReducerId,
2728
BuiltInUseRefId,
2829
BuiltInUseStateId,
@@ -818,6 +819,18 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
818819
returnValueKind: ValueKind.Frozen,
819820
}),
820821
],
822+
[
823+
'useOptimistic',
824+
addHook(DEFAULT_SHAPES, {
825+
positionalParams: [],
826+
restParam: Effect.Freeze,
827+
returnType: {kind: 'Object', shapeId: BuiltInUseOptimisticId},
828+
calleeEffect: Effect.Read,
829+
hookKind: 'useOptimistic',
830+
returnValueKind: ValueKind.Frozen,
831+
returnValueReason: ValueReason.State,
832+
}),
833+
],
821834
[
822835
'use',
823836
addFunction(

compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,6 +1887,18 @@ export function isStartTransitionType(id: Identifier): boolean {
18871887
);
18881888
}
18891889

1890+
export function isUseOptimisticType(id: Identifier): boolean {
1891+
return (
1892+
id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseOptimistic'
1893+
);
1894+
}
1895+
1896+
export function isSetOptimisticType(id: Identifier): boolean {
1897+
return (
1898+
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetOptimistic'
1899+
);
1900+
}
1901+
18901902
export function isSetActionStateType(id: Identifier): boolean {
18911903
return (
18921904
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState'
@@ -1920,7 +1932,8 @@ export function isStableType(id: Identifier): boolean {
19201932
isSetActionStateType(id) ||
19211933
isDispatcherType(id) ||
19221934
isUseRefType(id) ||
1923-
isStartTransitionType(id)
1935+
isStartTransitionType(id) ||
1936+
isSetOptimisticType(id)
19241937
);
19251938
}
19261939

@@ -1931,8 +1944,9 @@ export function isStableTypeContainer(id: Identifier): boolean {
19311944
}
19321945
return (
19331946
isUseStateType(id) || // setState
1934-
type_.shapeId === 'BuiltInUseActionState' || // setActionState
1947+
isUseActionStateType(id) || // setActionState
19351948
isUseReducerType(id) || // dispatcher
1949+
isUseOptimisticType(id) || // setOptimistic
19361950
type_.shapeId === 'BuiltInUseTransition' // startTransition
19371951
);
19381952
}
@@ -1952,6 +1966,7 @@ export function evaluatesToStableTypeOrContainer(
19521966
case 'useActionState':
19531967
case 'useRef':
19541968
case 'useTransition':
1969+
case 'useOptimistic':
19551970
return true;
19561971
}
19571972
}

compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ export type HookKind =
304304
| 'useTransition'
305305
| 'useImperativeHandle'
306306
| 'useEffectEvent'
307+
| 'useOptimistic'
307308
| 'Custom';
308309

309310
/*
@@ -399,6 +400,8 @@ export const BuiltInUseReducerId = 'BuiltInUseReducer';
399400
export const BuiltInDispatchId = 'BuiltInDispatch';
400401
export const BuiltInUseContextHookId = 'BuiltInUseContextHook';
401402
export const BuiltInUseTransitionId = 'BuiltInUseTransition';
403+
export const BuiltInUseOptimisticId = 'BuiltInUseOptimistic';
404+
export const BuiltInSetOptimisticId = 'BuiltInSetOptimistic';
402405
export const BuiltInStartTransitionId = 'BuiltInStartTransition';
403406
export const BuiltInFireId = 'BuiltInFire';
404407
export const BuiltInFireFunctionId = 'BuiltInFireFunction';
@@ -1186,6 +1189,25 @@ addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
11861189
],
11871190
]);
11881191

1192+
addObject(BUILTIN_SHAPES, BuiltInUseOptimisticId, [
1193+
['0', {kind: 'Poly'}],
1194+
[
1195+
'1',
1196+
addFunction(
1197+
BUILTIN_SHAPES,
1198+
[],
1199+
{
1200+
positionalParams: [],
1201+
restParam: Effect.Freeze,
1202+
returnType: PRIMITIVE_TYPE,
1203+
calleeEffect: Effect.Read,
1204+
returnValueKind: ValueKind.Primitive,
1205+
},
1206+
BuiltInSetOptimisticId,
1207+
),
1208+
],
1209+
]);
1210+
11891211
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
11901212
['0', {kind: 'Poly'}],
11911213
[
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validatePreserveExistingMemoizationGuarantees
6+
import {
7+
useCallback,
8+
useTransition,
9+
useState,
10+
useOptimistic,
11+
useActionState,
12+
useRef,
13+
useReducer,
14+
} from 'react';
15+
16+
function useFoo() {
17+
const [s, setState] = useState();
18+
const ref = useRef(null);
19+
const [t, startTransition] = useTransition();
20+
const [u, addOptimistic] = useOptimistic();
21+
const [v, dispatch] = useReducer(() => {}, null);
22+
const [isPending, dispatchAction] = useActionState(() => {}, null);
23+
24+
return useCallback(() => {
25+
dispatch();
26+
startTransition(() => {});
27+
addOptimistic();
28+
setState(null);
29+
dispatchAction();
30+
ref.current = true;
31+
}, []);
32+
}
33+
34+
export const FIXTURE_ENTRYPOINT = {
35+
fn: useFoo,
36+
params: [],
37+
};
38+
39+
```
40+
41+
## Code
42+
43+
```javascript
44+
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
45+
import {
46+
useCallback,
47+
useTransition,
48+
useState,
49+
useOptimistic,
50+
useActionState,
51+
useRef,
52+
useReducer,
53+
} from "react";
54+
55+
function useFoo() {
56+
const $ = _c(1);
57+
const [, setState] = useState();
58+
const ref = useRef(null);
59+
const [, startTransition] = useTransition();
60+
const [, addOptimistic] = useOptimistic();
61+
const [, dispatch] = useReducer(_temp, null);
62+
const [, dispatchAction] = useActionState(_temp2, null);
63+
let t0;
64+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
65+
t0 = () => {
66+
dispatch();
67+
startTransition(_temp3);
68+
addOptimistic();
69+
setState(null);
70+
dispatchAction();
71+
ref.current = true;
72+
};
73+
$[0] = t0;
74+
} else {
75+
t0 = $[0];
76+
}
77+
return t0;
78+
}
79+
function _temp3() {}
80+
function _temp2() {}
81+
function _temp() {}
82+
83+
export const FIXTURE_ENTRYPOINT = {
84+
fn: useFoo,
85+
params: [],
86+
};
87+
88+
```
89+
90+
### Eval output
91+
(kind: ok) "[[ function params=0 ]]"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// @validatePreserveExistingMemoizationGuarantees
2+
import {
3+
useCallback,
4+
useTransition,
5+
useState,
6+
useOptimistic,
7+
useActionState,
8+
useRef,
9+
useReducer,
10+
} from 'react';
11+
12+
function useFoo() {
13+
const [s, setState] = useState();
14+
const ref = useRef(null);
15+
const [t, startTransition] = useTransition();
16+
const [u, addOptimistic] = useOptimistic();
17+
const [v, dispatch] = useReducer(() => {}, null);
18+
const [isPending, dispatchAction] = useActionState(() => {}, null);
19+
20+
return useCallback(() => {
21+
dispatch();
22+
startTransition(() => {});
23+
addOptimistic();
24+
setState(null);
25+
dispatchAction();
26+
ref.current = true;
27+
}, []);
28+
}
29+
30+
export const FIXTURE_ENTRYPOINT = {
31+
fn: useFoo,
32+
params: [],
33+
};

0 commit comments

Comments
 (0)