@@ -19,6 +19,7 @@ import type {Interaction} from 'scheduler/src/Tracing';
1919import {
2020 warnAboutDeprecatedLifecycles ,
2121 enableUserTimingAPI ,
22+ enableUpdaterTracking ,
2223 enableSuspenseServerRenderer ,
2324 replayFailedUnitOfWorkWithInvokeGuardedCallback ,
2425 enableProfilerTimer ,
@@ -337,6 +338,16 @@ export function scheduleUpdateOnFiber(
337338 return ;
338339 }
339340
341+ if ( enableUpdaterTracking ) {
342+ const pendingUpdatersMap = root . pendingUpdatersMap ;
343+ let updaters = pendingUpdatersMap . get ( expirationTime ) ;
344+ if ( updaters == null ) {
345+ updaters = new Set ( ) ;
346+ pendingUpdatersMap . set ( expirationTime , updaters ) ;
347+ }
348+ updaters . add ( fiber ) ;
349+ }
350+
340351 root . pingTime = NoWork ;
341352
342353 checkForInterruption ( fiber , expirationTime ) ;
@@ -1292,6 +1303,12 @@ function commitRootImpl(root) {
12921303 // This usually means we've finished all the work, but it can also happen
12931304 // when something gets downprioritized during render, like a hidden tree.
12941305 root . lastPendingTime = firstPendingTimeBeforeCommit ;
1306+
1307+ if ( enableSchedulerTracing ) {
1308+ if ( firstPendingTimeBeforeCommit !== NoWork ) {
1309+ restorePendingUpdaters ( root , root . lastPendingTime ) ;
1310+ }
1311+ }
12951312 }
12961313
12971314 if ( root === workInProgressRoot ) {
@@ -1377,7 +1394,13 @@ function commitRootImpl(root) {
13771394 nextEffect = firstEffect ;
13781395 do {
13791396 if ( __DEV__ ) {
1380- invokeGuardedCallback ( null , commitMutationEffects , null ) ;
1397+ invokeGuardedCallback (
1398+ null ,
1399+ commitMutationEffects ,
1400+ null ,
1401+ root ,
1402+ expirationTime ,
1403+ ) ;
13811404 if ( hasCaughtError ( ) ) {
13821405 invariant ( nextEffect !== null , 'Should be working on an effect.' ) ;
13831406 const error = clearCaughtError ( ) ;
@@ -1386,7 +1409,7 @@ function commitRootImpl(root) {
13861409 }
13871410 } else {
13881411 try {
1389- commitMutationEffects ( ) ;
1412+ commitMutationEffects ( root , expirationTime ) ;
13901413 } catch ( error ) {
13911414 invariant ( nextEffect !== null , 'Should be working on an effect.' ) ;
13921415 captureCommitPhaseError ( nextEffect , error ) ;
@@ -1540,7 +1563,10 @@ function commitBeforeMutationEffects() {
15401563 }
15411564}
15421565
1543- function commitMutationEffects ( ) {
1566+ function commitMutationEffects (
1567+ root : FiberRoot ,
1568+ committedExpirationTime : ExpirationTime ,
1569+ ) {
15441570 // TODO: Should probably move the bulk of this function to commitWork.
15451571 while ( nextEffect !== null ) {
15461572 setCurrentDebugFiberInDEV ( nextEffect ) ;
@@ -1582,12 +1608,12 @@ function commitMutationEffects() {
15821608
15831609 // Update
15841610 const current = nextEffect . alternate ;
1585- commitWork ( current , nextEffect ) ;
1611+ commitWork ( root , current , nextEffect , committedExpirationTime ) ;
15861612 break ;
15871613 }
15881614 case Update : {
15891615 const current = nextEffect . alternate ;
1590- commitWork ( current , nextEffect ) ;
1616+ commitWork ( root , current , nextEffect , committedExpirationTime ) ;
15911617 break ;
15921618 }
15931619 case Deletion : {
@@ -1843,7 +1869,12 @@ export function retryTimedOutBoundary(boundaryFiber: Fiber) {
18431869 }
18441870}
18451871
1846- export function resolveRetryThenable ( boundaryFiber : Fiber , thenable : Thenable ) {
1872+ export function resolveRetryThenable (
1873+ boundaryFiber : Fiber ,
1874+ thenable : Thenable ,
1875+ root : FiberRoot ,
1876+ committedExpirationTime : ExpirationTime ,
1877+ ) {
18471878 let retryCache : WeakSet < Thenable > | Set < Thenable > | null ;
18481879 if ( enableSuspenseServerRenderer ) {
18491880 switch ( boundaryFiber . tag ) {
@@ -2161,6 +2192,24 @@ function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {
21612192 }
21622193}
21632194
2195+ export function restorePendingUpdaters (
2196+ root : FiberRoot ,
2197+ expirationTime : ExpirationTime ,
2198+ ) : void {
2199+ if ( ! enableUpdaterTracking ) {
2200+ return ;
2201+ }
2202+ const pendingUpdatersMap = root . pendingUpdatersMap ;
2203+ let updaters = pendingUpdatersMap . get ( expirationTime ) ;
2204+ if ( updaters == null ) {
2205+ updaters = new Set ( ) ;
2206+ pendingUpdatersMap . set ( expirationTime , updaters ) ;
2207+ }
2208+ root . memoizedUpdaters . forEach ( schedulingFiber => {
2209+ ( ( updaters : any ) : Set < Fiber > ) . add ( schedulingFiber ) ;
2210+ } ) ;
2211+ }
2212+
21642213export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV ;
21652214
21662215let componentsWithSuspendedDiscreteUpdates = null ;
@@ -2277,42 +2326,58 @@ function schedulePendingInteraction(root, expirationTime) {
22772326
22782327function startWorkOnPendingInteraction ( root , expirationTime ) {
22792328 // This is called when new work is started on a root.
2280- if ( ! enableSchedulerTracing ) {
2281- return ;
2282- }
22832329
2284- // Determine which interactions this batch of work currently includes, So that
2285- // we can accurately attribute time spent working on it, And so that cascading
2286- // work triggered during the render phase will be associated with it.
2287- const interactions : Set < Interaction > = new Set();
2288- root.pendingInteractionMap.forEach(
2289- (scheduledInteractions, scheduledExpirationTime) => {
2330+ if ( enableUpdaterTracking ) {
2331+ const memoizedUpdaters : Set < Fiber > = new Set();
2332+ const pendingUpdatersMap = root.pendingUpdatersMap;
2333+ pendingUpdatersMap.forEach((updaters, scheduledExpirationTime) => {
22902334 if ( scheduledExpirationTime >= expirationTime ) {
2291- scheduledInteractions . forEach ( interaction =>
2292- interactions . add ( interaction ) ,
2293- ) ;
2335+ pendingUpdatersMap . delete ( scheduledExpirationTime ) ;
2336+ updaters . forEach ( fiber => memoizedUpdaters . add ( fiber ) ) ;
22942337 }
2295- } ,
2296- ) ;
2338+ } ) ;
22972339
2298- // Store the current set of interactions on the FiberRoot for a few reasons:
2299- // We can re-use it in hot functions like renderRoot() without having to
2300- // recalculate it. We will also use it in commitWork() to pass to any Profiler
2301- // onRender () hooks. This also provides DevTools with a way to access it when
2302- // the onCommitRoot() hook is called.
2303- root . memoizedInteractions = interactions ;
2340+ // Store the current set of interactions on the FiberRoot for a few reasons:
2341+ // We can re-use it in hot functions like renderRoot() without having to
2342+ // recalculate it. This also provides DevTools with a way to access it when
2343+ // the onCommitRoot () hook is called.
2344+ root . memoizedUpdaters = memoizedUpdaters ;
2345+ }
23042346
2305- if ( interactions . size > 0 ) {
2306- const subscriber = __subscriberRef . current ;
2307- if ( subscriber !== null ) {
2308- const threadID = computeThreadID ( root , expirationTime ) ;
2309- try {
2310- subscriber . onWorkStarted ( interactions , threadID ) ;
2311- } catch ( error ) {
2312- // If the subscriber throws, rethrow it in a separate task
2313- scheduleCallback ( ImmediatePriority , ( ) => {
2314- throw error ;
2315- } ) ;
2347+ if ( enableSchedulerTracing ) {
2348+ // Determine which interactions this batch of work currently includes, So that
2349+ // we can accurately attribute time spent working on it, And so that cascading
2350+ // work triggered during the render phase will be associated with it.
2351+ const interactions : Set < Interaction > = new Set();
2352+ root.pendingInteractionMap.forEach(
2353+ (scheduledInteractions, scheduledExpirationTime) => {
2354+ if ( scheduledExpirationTime >= expirationTime ) {
2355+ scheduledInteractions . forEach ( interaction =>
2356+ interactions . add ( interaction ) ,
2357+ ) ;
2358+ }
2359+ } ,
2360+ ) ;
2361+
2362+ // Store the current set of interactions on the FiberRoot for a few reasons:
2363+ // We can re-use it in hot functions like renderRoot() without having to
2364+ // recalculate it. We will also use it in commitWork() to pass to any Profiler
2365+ // onRender() hooks. This also provides DevTools with a way to access it when
2366+ // the onCommitRoot() hook is called.
2367+ root . memoizedInteractions = interactions ;
2368+
2369+ if ( interactions . size > 0 ) {
2370+ const subscriber = __subscriberRef . current ;
2371+ if ( subscriber !== null ) {
2372+ const threadID = computeThreadID ( root , expirationTime ) ;
2373+ try {
2374+ subscriber . onWorkStarted ( interactions , threadID ) ;
2375+ } catch ( error ) {
2376+ // If the subscriber throws, rethrow it in a separate task
2377+ scheduleCallback ( ImmediatePriority , ( ) => {
2378+ throw error ;
2379+ } ) ;
2380+ }
23162381 }
23172382 }
23182383 }
0 commit comments