diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts index 884372b986ea8..e9066f85b8193 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts @@ -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( diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 84671712e9305..e61665ce4c6bb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -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) ); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts index 3d377dba59dc9..9554878578ca0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts @@ -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'}], [ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.expect.md new file mode 100644 index 0000000000000..941c37bc3f29f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.expect.md @@ -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 ]]" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.ts new file mode 100644 index 0000000000000..a822d68dfc82d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/preserve-use-memo-transition.ts @@ -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: [], +};