[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) {