[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: 0e76a64f2d
Pull Request resolved: https://github.com/facebook/react/pull/30681
This commit is contained in:
Mike Vitousek
2024-08-14 13:54:39 -04:00
parent 179197a22a
commit dd8e0ba857
5 changed files with 109 additions and 1 deletions
@@ -18,6 +18,7 @@ import {
BuiltInUseReducerId,
BuiltInUseRefId,
BuiltInUseStateId,
BuiltInUseTransitionId,
ShapeRegistry,
addFunction,
addHook,
@@ -425,6 +426,17 @@ const REACT_APIS: Array<[string, BuiltInType]> = [
BuiltInUseInsertionEffectHookId,
),
],
[
'useTransition',
addHook(DEFAULT_SHAPES, {
positionalParams: [],
restParam: null,
returnType: {kind: 'Object', shapeId: BuiltInUseTransitionId},
calleeEffect: Effect.Read,
hookKind: 'useTransition',
returnValueKind: ValueKind.Frozen,
}),
],
[
'use',
addFunction(
@@ -1601,6 +1601,12 @@ export function isUseActionStateType(id: Identifier): boolean {
);
}
export function isStartTransitionType(id: Identifier): boolean {
return (
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition'
);
}
export function isSetActionStateType(id: Identifier): boolean {
return (
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState'
@@ -1620,7 +1626,8 @@ export function isStableType(id: Identifier): boolean {
isSetStateType(id) ||
isSetActionStateType(id) ||
isDispatcherType(id) ||
isUseRefType(id)
isUseRefType(id) ||
isStartTransitionType(id)
);
}
@@ -126,6 +126,7 @@ export type HookKind =
| 'useInsertionEffect'
| 'useMemo'
| 'useCallback'
| 'useTransition'
| 'Custom';
/*
@@ -209,6 +210,8 @@ export const BuiltInUseOperatorId = 'BuiltInUseOperator';
export const BuiltInUseReducerId = 'BuiltInUseReducer';
export const BuiltInDispatchId = 'BuiltInDispatch';
export const BuiltInUseContextHookId = 'BuiltInUseContextHook';
export const BuiltInUseTransitionId = 'BuiltInUseTransition';
export const BuiltInStartTransitionId = 'BuiltInStartTransition';
// ShapeRegistry with default definitions for built-ins.
export const BUILTIN_SHAPES: ShapeRegistry = new Map();
@@ -444,6 +447,25 @@ addObject(BUILTIN_SHAPES, BuiltInUseStateId, [
],
]);
addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
['0', {kind: 'Primitive'}],
[
'1',
addFunction(
BUILTIN_SHAPES,
[],
{
positionalParams: [],
restParam: null,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
},
BuiltInStartTransitionId,
),
],
]);
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
['0', {kind: 'Poly'}],
[
@@ -0,0 +1,52 @@
## Input
```javascript
// @validatePreserveExistingMemoizationGuarantees
import {useCallback, useTransition} from 'react';
function useFoo() {
const [t, start] = useTransition();
return useCallback(() => {
start();
}, []);
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees
import { useCallback, useTransition } from "react";
function useFoo() {
const $ = _c(1);
const [t, start] = useTransition();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
start();
};
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};
```
### Eval output
(kind: ok) "[[ function params=0 ]]"
@@ -0,0 +1,15 @@
// @validatePreserveExistingMemoizationGuarantees
import {useCallback, useTransition} from 'react';
function useFoo() {
const [t, start] = useTransition();
return useCallback(() => {
start();
}, []);
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [],
};