@samitouri / QOS-React / commits / 1fb0d06878

[Devtools][Transition Tracing] Add Transition callbacks to createRoot (#23276)

- Add the type of transition tracing callbacks - Add transition tracing callbacks as an option to `createRoot` - Add transition tracing callbacks on the root - Add option to pass transition tracing callbacks to createReactNoop

Luna Ruan committed Feb 11, 2022 at 13:15 UTC 1fb0d06878416d321182ddb4601231982e7433c9
11 files changed +129 -8
packages/react-dom/src/client/ReactDOMLegacy.js
+2 -1
@@ -127,7 +127,8 @@ function legacyCreateRootFromDOMContainer(
127 false, // isStrictMode
128 false, // concurrentUpdatesByDefaultOverride,
129 '', // identifierPrefix
130 - noopOnRecoverableError,
130 + noopOnRecoverableError, // onRecoverableError
131 + null, // transitionCallbacks
132 );
133 markContainerAsRoot(root.current, container);
134
packages/react-dom/src/client/ReactDOMRoot.js
+13 -1
@@ -9,7 +9,10 @@
9
10 import type {Container} from './ReactDOMHostConfig';
11 import type {MutableSource, ReactNodeList} from 'shared/ReactTypes';
12 -import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
12 +import type {
13 + FiberRoot,
14 + TransitionTracingCallbacks,
15 +} from 'react-reconciler/src/ReactInternalTypes';
16
17 import {queueExplicitHydrationTarget} from '../events/ReactDOMEventReplaying';
18
@@ -25,6 +28,7 @@ export type CreateRootOptions = {
28 unstable_concurrentUpdatesByDefault?: boolean,
29 identifierPrefix?: string,
30 onRecoverableError?: (error: mixed) => void,
31 + transitionCallbacks?: TransitionTracingCallbacks,
32 ...
33 };
34
@@ -158,6 +162,8 @@ export function createRoot(
162 let concurrentUpdatesByDefaultOverride = false;
163 let identifierPrefix = '';
164 let onRecoverableError = defaultOnRecoverableError;
165 + let transitionCallbacks = null;
166 +
167 if (options !== null && options !== undefined) {
168 if (__DEV__) {
169 if ((options: any).hydrate) {
@@ -181,6 +187,9 @@ export function createRoot(
187 if (options.onRecoverableError !== undefined) {
188 onRecoverableError = options.onRecoverableError;
189 }
190 + if (options.transitionCallbacks !== undefined) {
191 + transitionCallbacks = options.transitionCallbacks;
192 + }
193 }
194
195 const root = createContainer(
@@ -192,6 +201,7 @@ export function createRoot(
201 concurrentUpdatesByDefaultOverride,
202 identifierPrefix,
203 onRecoverableError,
204 + transitionCallbacks,
205 );
206 markContainerAsRoot(root.current, container);
207
@@ -260,6 +270,8 @@ export function hydrateRoot(
270 concurrentUpdatesByDefaultOverride,
271 identifierPrefix,
272 onRecoverableError,
273 + // TODO(luna) Support hydration later
274 + null,
275 );
276 markContainerAsRoot(root.current, container);
277 // This can't be a comment node since hydration doesn't work on comment nodes anyway.
packages/react-native-renderer/src/ReactFabric.js
+1
@@ -221,6 +221,7 @@ function render(
221 null,
222 '',
223 onRecoverableError,
224 + null,
225 );
226 roots.set(containerTag, root);
227 }
packages/react-native-renderer/src/ReactNativeRenderer.js
+1
@@ -217,6 +217,7 @@ function render(
217 null,
218 '',
219 onRecoverableError,
220 + null,
221 );
222 roots.set(containerTag, root);
223 }
packages/react-noop-renderer/src/createReactNoop.js
+12 -2
@@ -14,7 +14,10 @@
14 * environment.
15 */
16
17 -import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
17 +import type {
18 + Fiber,
19 + TransitionTracingCallbacks,
20 +} from 'react-reconciler/src/ReactInternalTypes';
21 import type {UpdateQueue} from 'react-reconciler/src/ReactUpdateQueue';
22 import type {ReactNodeList, OffscreenMode} from 'shared/ReactTypes';
23 import type {RootTag} from 'react-reconciler/src/ReactRootTags';
@@ -64,6 +67,10 @@ type TextInstance = {|
67 context: HostContext,
68 |};
69 type HostContext = Object;
70 +type CreateRootOptions = {
71 + transitionCallbacks?: TransitionTracingCallbacks,
72 + ...
73 +};
74
75 const NO_CONTEXT = {};
76 const UPPERCASE_CONTEXT = {};
@@ -980,7 +987,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
987 },
988
989 // TODO: Replace ReactNoop.render with createRoot + root.render
983 - createRoot() {
990 + createRoot(options?: CreateRootOptions) {
991 const container = {
992 rootID: '' + idCounter++,
993 pendingChildren: [],
@@ -995,6 +1002,9 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1002 false,
1003 '',
1004 onRecoverableError,
1005 + options && options.transitionCallbacks
1006 + ? options.transitionCallbacks
1007 + : null,
1008 );
1009 return {
1010 _Scheduler: Scheduler,
packages/react-reconciler/src/ReactFiberReconciler.new.js
+7 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + Fiber,
12 + SuspenseHydrationCallbacks,
13 + TransitionTracingCallbacks,
14 +} from './ReactInternalTypes';
15 import type {FiberRoot} from './ReactInternalTypes';
16 import type {RootTag} from './ReactRootTags';
17 import type {
@@ -246,6 +250,7 @@ export function createContainer(
250 concurrentUpdatesByDefaultOverride: null | boolean,
251 identifierPrefix: string,
252 onRecoverableError: (error: mixed) => void,
253 + transitionCallbacks: null | TransitionTracingCallbacks,
254 ): OpaqueRoot {
255 return createFiberRoot(
256 containerInfo,
@@ -256,6 +261,7 @@ export function createContainer(
261 concurrentUpdatesByDefaultOverride,
262 identifierPrefix,
263 onRecoverableError,
264 + transitionCallbacks,
265 );
266 }
267
packages/react-reconciler/src/ReactFiberReconciler.old.js
+7 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {Fiber, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + Fiber,
12 + SuspenseHydrationCallbacks,
13 + TransitionTracingCallbacks,
14 +} from './ReactInternalTypes';
15 import type {FiberRoot} from './ReactInternalTypes';
16 import type {RootTag} from './ReactRootTags';
17 import type {
@@ -246,6 +250,7 @@ export function createContainer(
250 concurrentUpdatesByDefaultOverride: null | boolean,
251 identifierPrefix: string,
252 onRecoverableError: (error: mixed) => void,
253 + transitionCallbacks: null | TransitionTracingCallbacks,
254 ): OpaqueRoot {
255 return createFiberRoot(
256 containerInfo,
@@ -256,6 +261,7 @@ export function createContainer(
261 concurrentUpdatesByDefaultOverride,
262 identifierPrefix,
263 onRecoverableError,
264 + transitionCallbacks,
265 );
266 }
267
packages/react-reconciler/src/ReactFiberRoot.new.js
+15 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {FiberRoot, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + FiberRoot,
12 + SuspenseHydrationCallbacks,
13 + TransitionTracingCallbacks,
14 +} from './ReactInternalTypes';
15 import type {RootTag} from './ReactRootTags';
16
17 import {noTimeout, supportsHydration} from './ReactFiberHostConfig';
@@ -25,6 +29,7 @@ import {
29 enableProfilerCommitHooks,
30 enableProfilerTimer,
31 enableUpdaterTracking,
32 + enableTransitionTracing,
33 } from 'shared/ReactFeatureFlags';
34 import {initializeUpdateQueue} from './ReactUpdateQueue.new';
35 import {LegacyRoot, ConcurrentRoot} from './ReactRootTags';
@@ -78,6 +83,10 @@ function FiberRootNode(
83 this.hydrationCallbacks = null;
84 }
85
86 + if (enableTransitionTracing) {
87 + this.transitionCallbacks = null;
88 + }
89 +
90 if (enableProfilerTimer && enableProfilerCommitHooks) {
91 this.effectDuration = 0;
92 this.passiveEffectDuration = 0;
@@ -116,6 +125,7 @@ export function createFiberRoot(
125 // single type, like a DynamicHostConfig that is defined by the renderer.
126 identifierPrefix: string,
127 onRecoverableError: null | ((error: mixed) => void),
128 + transitionCallbacks: null | TransitionTracingCallbacks,
129 ): FiberRoot {
130 const root: FiberRoot = (new FiberRootNode(
131 containerInfo,
@@ -128,6 +138,10 @@ export function createFiberRoot(
138 root.hydrationCallbacks = hydrationCallbacks;
139 }
140
141 + if (enableTransitionTracing) {
142 + root.transitionCallbacks = transitionCallbacks;
143 + }
144 +
145 // Cyclic construction. This cheats the type system right now because
146 // stateNode is any.
147 const uninitializedFiber = createHostRootFiber(
packages/react-reconciler/src/ReactFiberRoot.old.js
+15 -1
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import type {FiberRoot, SuspenseHydrationCallbacks} from './ReactInternalTypes';
10 +import type {
11 + FiberRoot,
12 + SuspenseHydrationCallbacks,
13 + TransitionTracingCallbacks,
14 +} from './ReactInternalTypes';
15 import type {RootTag} from './ReactRootTags';
16
17 import {noTimeout, supportsHydration} from './ReactFiberHostConfig';
@@ -25,6 +29,7 @@ import {
29 enableProfilerCommitHooks,
30 enableProfilerTimer,
31 enableUpdaterTracking,
32 + enableTransitionTracing,
33 } from 'shared/ReactFeatureFlags';
34 import {initializeUpdateQueue} from './ReactUpdateQueue.old';
35 import {LegacyRoot, ConcurrentRoot} from './ReactRootTags';
@@ -78,6 +83,10 @@ function FiberRootNode(
83 this.hydrationCallbacks = null;
84 }
85
86 + if (enableTransitionTracing) {
87 + this.transitionCallbacks = null;
88 + }
89 +
90 if (enableProfilerTimer && enableProfilerCommitHooks) {
91 this.effectDuration = 0;
92 this.passiveEffectDuration = 0;
@@ -116,6 +125,7 @@ export function createFiberRoot(
125 // single type, like a DynamicHostConfig that is defined by the renderer.
126 identifierPrefix: string,
127 onRecoverableError: null | ((error: mixed) => void),
128 + transitionCallbacks: null | TransitionTracingCallbacks,
129 ): FiberRoot {
130 const root: FiberRoot = (new FiberRootNode(
131 containerInfo,
@@ -128,6 +138,10 @@ export function createFiberRoot(
138 root.hydrationCallbacks = hydrationCallbacks;
139 }
140
141 + if (enableTransitionTracing) {
142 + root.transitionCallbacks = transitionCallbacks;
143 + }
144 +
145 // Cyclic construction. This cheats the type system right now because
146 // stateNode is any.
147 const uninitializedFiber = createHostRootFiber(
packages/react-reconciler/src/ReactInternalTypes.js
+55
@@ -268,6 +268,60 @@ type SuspenseCallbackOnlyFiberRootProperties = {|
268 hydrationCallbacks: null | SuspenseHydrationCallbacks,
269 |};
270
271 +export type TransitionTracingCallbacks = {
272 + onTransitionStart?: (transitionName: string, startTime: number) => void,
273 + onTransitionProgress?: (
274 + transitionName: string,
275 + startTime: number,
276 + currentTime: number,
277 + pending: Array<{name: null | string}>,
278 + ) => void,
279 + onTransitionIncomplete?: (
280 + transitionName: string,
281 + startTime: number,
282 + deletions: Array<{
283 + type: string,
284 + name?: string,
285 + newName?: string,
286 + endTime: number,
287 + }>,
288 + ) => void,
289 + onTransitionComplete?: (
290 + transitionName: string,
291 + startTime: number,
292 + endTime: number,
293 + ) => void,
294 + onMarkerProgress?: (
295 + transitionName: string,
296 + marker: string,
297 + startTime: number,
298 + currentTime: number,
299 + pending: Array<{name: null | string}>,
300 + ) => void,
301 + onMarkerIncomplete?: (
302 + transitionName: string,
303 + marker: string,
304 + startTime: number,
305 + deletions: Array<{
306 + type: string,
307 + name?: string,
308 + newName?: string,
309 + endTime: number,
310 + }>,
311 + ) => void,
312 + onMarkerComplete?: (
313 + transitionName: string,
314 + marker: string,
315 + startTime: number,
316 + endTime: number,
317 + ) => void,
318 +};
319 +
320 +// The following fields are only used in transition tracing in Profile builds
321 +type TransitionTracingOnlyFiberRootProperties = {|
322 + transitionCallbacks: null | TransitionTracingCallbacks,
323 +|};
324 +
325 // Exported FiberRoot type includes all properties,
326 // To avoid requiring potentially error-prone :any casts throughout the project.
327 // The types are defined separately within this file to ensure they stay in sync.
@@ -275,6 +329,7 @@ export type FiberRoot = {
329 ...BaseFiberRootProperties,
330 ...SuspenseCallbackOnlyFiberRootProperties,
331 ...UpdaterTrackingOnlyFiberRootProperties,
332 + ...TransitionTracingOnlyFiberRootProperties,
333 ...
334 };
335
packages/react-test-renderer/src/ReactTestRenderer.js
+1
@@ -479,6 +479,7 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
479 concurrentUpdatesByDefault,
480 '',
481 onRecoverableError,
482 + null,
483 );
484
485 if (root == null) {