From a014d90db50c3dfdfb2da194e80d046f051d03b3 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 10 Jan 2022 17:37:44 -0500 Subject: [PATCH] add transition callbacks to root --- .../react-dom/src/client/ReactDOMLegacy.js | 1 + packages/react-dom/src/client/ReactDOMRoot.js | 13 ++++- .../src/ReactFiberReconciler.new.js | 8 ++- .../src/ReactFiberReconciler.old.js | 7 ++- .../src/ReactFiberRoot.new.js | 16 +++++- .../src/ReactFiberWorkLoop.new.js | 4 ++ .../src/ReactInternalTypes.js | 55 +++++++++++++++++++ 7 files changed, 100 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMLegacy.js b/packages/react-dom/src/client/ReactDOMLegacy.js index 05ae0d5ce4f45..cb95101401ea4 100644 --- a/packages/react-dom/src/client/ReactDOMLegacy.js +++ b/packages/react-dom/src/client/ReactDOMLegacy.js @@ -122,6 +122,7 @@ function legacyCreateRootFromDOMContainer( false, // isStrictMode false, // concurrentUpdatesByDefaultOverride, '', // identifierPrefix + null, ); markContainerAsRoot(root.current, container); diff --git a/packages/react-dom/src/client/ReactDOMRoot.js b/packages/react-dom/src/client/ReactDOMRoot.js index 800eeba0d018d..db515494b17af 100644 --- a/packages/react-dom/src/client/ReactDOMRoot.js +++ b/packages/react-dom/src/client/ReactDOMRoot.js @@ -9,7 +9,10 @@ import type {Container} from './ReactDOMHostConfig'; import type {MutableSource, ReactNodeList} from 'shared/ReactTypes'; -import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; +import type { + FiberRoot, + TransitionTracingCallbacks, +} from 'react-reconciler/src/ReactInternalTypes'; import {queueExplicitHydrationTarget} from '../events/ReactDOMEventReplaying'; @@ -24,6 +27,7 @@ export type CreateRootOptions = { unstable_strictMode?: boolean, unstable_concurrentUpdatesByDefault?: boolean, identifierPrefix?: string, + transitionCallbacks?: TransitionTracingCallbacks, ... }; @@ -143,6 +147,7 @@ export function createRoot( let isStrictMode = false; let concurrentUpdatesByDefaultOverride = false; let identifierPrefix = ''; + let transitionCallbacks = null; if (options !== null && options !== undefined) { if (__DEV__) { if ((options: any).hydrate) { @@ -163,6 +168,9 @@ export function createRoot( if (options.identifierPrefix !== undefined) { identifierPrefix = options.identifierPrefix; } + if (options.transitionCallbacks !== undefined) { + transitionCallbacks = options.transitionCallbacks; + } } const root = createContainer( @@ -173,6 +181,7 @@ export function createRoot( isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, + transitionCallbacks, ); markContainerAsRoot(root.current, container); @@ -236,6 +245,8 @@ export function hydrateRoot( isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, + // TODO(luna) Support hydration later + null, ); markContainerAsRoot(root.current, container); // This can't be a comment node since hydration doesn't work on comment nodes anyway. diff --git a/packages/react-reconciler/src/ReactFiberReconciler.new.js b/packages/react-reconciler/src/ReactFiberReconciler.new.js index 1b8b9502de3ee..4c0a2ae33a48e 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.new.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.new.js @@ -7,7 +7,11 @@ * @flow */ -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes'; +import type { + Fiber, + SuspenseHydrationCallbacks, + TransitionTracingCallbacks, +} from './ReactInternalTypes'; import type {FiberRoot} from './ReactInternalTypes'; import type {RootTag} from './ReactRootTags'; import type { @@ -242,6 +246,7 @@ export function createContainer( isStrictMode: boolean, concurrentUpdatesByDefaultOverride: null | boolean, identifierPrefix: string, + transitionCallbacks: null | TransitionTracingCallbacks, ): OpaqueRoot { return createFiberRoot( containerInfo, @@ -251,6 +256,7 @@ export function createContainer( isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, + transitionCallbacks, ); } diff --git a/packages/react-reconciler/src/ReactFiberReconciler.old.js b/packages/react-reconciler/src/ReactFiberReconciler.old.js index 8649ff6989841..52ad92e608e54 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.old.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.old.js @@ -7,7 +7,11 @@ * @flow */ -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes'; +import type { + Fiber, + SuspenseHydrationCallbacks, + TransitionTracingCallbacks, +} from './ReactInternalTypes'; import type {FiberRoot} from './ReactInternalTypes'; import type {RootTag} from './ReactRootTags'; import type { @@ -242,6 +246,7 @@ export function createContainer( isStrictMode: boolean, concurrentUpdatesByDefaultOverride: null | boolean, identifierPrefix: string, + transitionCallbacks: null | TransitionTracingCallbacks, ): OpaqueRoot { return createFiberRoot( containerInfo, diff --git a/packages/react-reconciler/src/ReactFiberRoot.new.js b/packages/react-reconciler/src/ReactFiberRoot.new.js index 9e9feb45d9b03..66cc1caebec5e 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.new.js +++ b/packages/react-reconciler/src/ReactFiberRoot.new.js @@ -7,7 +7,11 @@ * @flow */ -import type {FiberRoot, SuspenseHydrationCallbacks} from './ReactInternalTypes'; +import type { + FiberRoot, + SuspenseHydrationCallbacks, + TransitionTracingCallbacks, +} from './ReactInternalTypes'; import type {RootTag} from './ReactRootTags'; import {noTimeout, supportsHydration} from './ReactFiberHostConfig'; @@ -25,6 +29,7 @@ import { enableProfilerCommitHooks, enableProfilerTimer, enableUpdaterTracking, + enableTransitionTracing, } from 'shared/ReactFeatureFlags'; import {initializeUpdateQueue} from './ReactUpdateQueue.new'; import {LegacyRoot, ConcurrentRoot} from './ReactRootTags'; @@ -71,6 +76,10 @@ function FiberRootNode(containerInfo, tag, hydrate, identifierPrefix) { this.hydrationCallbacks = null; } + if (enableTransitionTracing) { + this.transitionCallbacks = null; + } + if (enableProfilerTimer && enableProfilerCommitHooks) { this.effectDuration = 0; this.passiveEffectDuration = 0; @@ -104,6 +113,7 @@ export function createFiberRoot( isStrictMode: boolean, concurrentUpdatesByDefaultOverride: null | boolean, identifierPrefix: string, + transitionCallbacks: null | TransitionTracingCallbacks, ): FiberRoot { const root: FiberRoot = (new FiberRootNode( containerInfo, @@ -115,6 +125,10 @@ export function createFiberRoot( root.hydrationCallbacks = hydrationCallbacks; } + if (enableTransitionTracing) { + root.transitionCallbacks = transitionCallbacks; + } + // Cyclic construction. This cheats the type system right now because // stateNode is any. const uninitializedFiber = createHostRootFiber( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index 740ed6dca40a5..3c443c86d2142 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -33,6 +33,7 @@ import { enableUpdaterTracking, warnOnSubscriptionInsideStartTransition, enableCache, + enableTransitionTracing, } from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import is from 'shared/objectIs'; @@ -269,6 +270,9 @@ let workInProgress: Fiber | null = null; // The lanes we're rendering let workInProgressRootRenderLanes: Lanes = NoLanes; +// TODO(luna) Figure out the type of this +let currentPendingTransitionCallbacks: Array<{}> | null = null; + // Stack that allows components to change the render lanes for its subtree // This is a superset of the lanes we started working on at the root. The only // case where it's different from `workInProgressRootRenderLanes` is when we diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index 13965720b7cd3..67872a4f6bd83 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -266,6 +266,60 @@ type SuspenseCallbackOnlyFiberRootProperties = {| hydrationCallbacks: null | SuspenseHydrationCallbacks, |}; +export type TransitionTracingCallbacks = { + onTransitionStart?: (transitionName: string, startTime: number) => void, + onTransitionProgress?: ( + transitionName: string, + startTime: number, + currentTime: number, + pending: Array<{name: null | string}>, + ) => void, + onTransitionIncomplete?: ( + transitionName: string, + startTime: number, + deletions: Array<{ + type: string, + name?: string, + newName?: string, + endTime: number, + }>, + ) => void, + onTransitionComplete?: ( + transitionName: string, + startTime: number, + endTime: number, + ) => void, + onMarkerProgress?: ( + transitionName: string, + marker: string, + startTime: number, + currentTime: number, + pending: Array<{name: null | string}>, + ) => void, + onMarkerIncomplete?: ( + transitionName: string, + marker: string, + startTime: number, + deletions: Array<{ + type: string, + name?: string, + newName?: string, + endTime: number, + }>, + ) => void, + onMarkerComplete?: ( + transitionName: string, + marker: string, + startTime: number, + endTime: number, + ) => void, +}; + +// The following fields are only used in transition tracing in Profile builds +type TransitionTracingOnlyFiberRootProperties = {| + transitionCallbacks: null | TransitionTracingCallbacks, +|}; + // Exported FiberRoot type includes all properties, // To avoid requiring potentially error-prone :any casts throughout the project. // The types are defined separately within this file to ensure they stay in sync. @@ -273,6 +327,7 @@ export type FiberRoot = { ...BaseFiberRootProperties, ...SuspenseCallbackOnlyFiberRootProperties, ...UpdaterTrackingOnlyFiberRootProperties, + ...TransitionTracingOnlyFiberRootProperties, ... };