[compiler] Support for useTransition
Summary: UseTransition is a builtin hook that returns a stable value, like useState. This PR represents that in Forget, and marks the startTransition function as stable. ghstack-source-id: 0e76a64f2d0c86a4eb55c620922b4698250bb5c3 Pull Request resolved: https://github.com/facebook/react/pull/30681
Mike Vitousek committed
Aug 14, 2024 at 13:54 UTC
dd8e0ba857fcd546d677c7283d5f35a663bc8d02
5 files changed
+109
-1
compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts
+12
@@ -18,6 +18,7 @@ import {
18
BuiltInUseReducerId,
19
BuiltInUseRefId,
20
BuiltInUseStateId,
21
+ BuiltInUseTransitionId,
22
ShapeRegistry,
23
addFunction,
24
addHook,
@@ -425,6 +426,17 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
426
BuiltInUseInsertionEffectHookId,
427
),
428
],
429
+ [
430
+ 'useTransition',
431
+ addHook(DEFAULT_SHAPES, {
432
+ positionalParams: [],
433
+ restParam: null,
434
+ returnType: {kind: 'Object', shapeId: BuiltInUseTransitionId},
435
+ calleeEffect: Effect.Read,
436
+ hookKind: 'useTransition',
437
+ returnValueKind: ValueKind.Frozen,
438
+ }),
439
+ ],
440
[
441
'use',
442
addFunction(
compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts
+8
-1
@@ -1601,6 +1601,12 @@ export function isUseActionStateType(id: Identifier): boolean {
1601
);
1602
}
1603
1604
+export function isStartTransitionType(id: Identifier): boolean {
1605
+ return (
1606
+ id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition'
1607
+ );
1608
+}
1609
+
1610
export function isSetActionStateType(id: Identifier): boolean {
1611
return (
1612
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState'
@@ -1620,7 +1626,8 @@ export function isStableType(id: Identifier): boolean {
1626
isSetStateType(id) ||
1627
isSetActionStateType(id) ||
1628
isDispatcherType(id) ||
1623
- isUseRefType(id)
1629
+ isUseRefType(id) ||
1630
+ isStartTransitionType(id)
1631
);
1632
}
1633
compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
+22
@@ -126,6 +126,7 @@ export type HookKind =
126
| 'useInsertionEffect'
127
| 'useMemo'
128
| 'useCallback'
129
+ | 'useTransition'
130
| 'Custom';
131
132
/*
@@ -209,6 +210,8 @@ export const BuiltInUseOperatorId = 'BuiltInUseOperator';
210
export const BuiltInUseReducerId = 'BuiltInUseReducer';
211
export const BuiltInDispatchId = 'BuiltInDispatch';
212
export const BuiltInUseContextHookId = 'BuiltInUseContextHook';
213
+export const BuiltInUseTransitionId = 'BuiltInUseTransition';
214
+export const BuiltInStartTransitionId = 'BuiltInStartTransition';
215
216
// ShapeRegistry with default definitions for built-ins.
217
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
@@ -444,6 +447,25 @@ addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
447
],
448
]);
449
450
+addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
451
+ ['0', {kind: 'Primitive'}],
452
+ [
453
+ '1',
454
+ addFunction(
455
+ BUILTIN_SHAPES,
456
+ [],
457
+ {
458
+ positionalParams: [],
459
+ restParam: null,
460
+ returnType: PRIMITIVE_TYPE,
461
+ calleeEffect: Effect.Read,
462
+ returnValueKind: ValueKind.Primitive,
463
+ },
464
+ BuiltInStartTransitionId,
465
+ ),
466
+ ],
467
+]);
468
+
469
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
470
['0', {kind: 'Poly'}],
471
[
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.expect.md
new
+52
@@ -0,0 +1,52 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @validatePreserveExistingMemoizationGuarantees
6
+import {useCallback, useTransition} from 'react';
7
+
8
+function useFoo() {
9
+ const [t, start] = useTransition();
10
+
11
+ return useCallback(() => {
12
+ start();
13
+ }, []);
14
+}
15
+
16
+export const FIXTURE_ENTRYPOINT = {
17
+ fn: useFoo,
18
+ params: [],
19
+};
20
+
21
+```
22
+
23
+## Code
24
+
25
+```javascript
26
+import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
27
+import { useCallback, useTransition } from "react";
28
+
29
+function useFoo() {
30
+ const $ = _c(1);
31
+ const [t, start] = useTransition();
32
+ let t0;
33
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
34
+ t0 = () => {
35
+ start();
36
+ };
37
+ $[0] = t0;
38
+ } else {
39
+ t0 = $[0];
40
+ }
41
+ return t0;
42
+}
43
+
44
+export const FIXTURE_ENTRYPOINT = {
45
+ fn: useFoo,
46
+ params: [],
47
+};
48
+
49
+```
50
+
51
+### Eval output
52
+(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-transition.ts
new
+15
@@ -0,0 +1,15 @@
1
+// @validatePreserveExistingMemoizationGuarantees
2
+import {useCallback, useTransition} from 'react';
3
+
4
+function useFoo() {
5
+ const [t, start] = useTransition();
6
+
7
+ return useCallback(() => {
8
+ start();
9
+ }, []);
10
+}
11
+
12
+export const FIXTURE_ENTRYPOINT = {
13
+ fn: useFoo,
14
+ params: [],
15
+};