@@ -14,6 +14,7 @@ import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig';
1414import type { Thenable } from './ReactFiberWorkLoop' ;
1515import type { Interaction } from 'scheduler/src/Tracing' ;
1616import type { SuspenseHydrationCallbacks } from './ReactFiberSuspenseComponent' ;
17+ import type { ReactPriorityLevel } from './SchedulerWithReactIntegration' ;
1718
1819import { noTimeout } from './ReactFiberHostConfig' ;
1920import { createHostRootFiber } from './ReactFiber' ;
@@ -23,6 +24,7 @@ import {
2324 enableSuspenseCallback ,
2425} from 'shared/ReactFeatureFlags' ;
2526import { unstable_getThreadID } from 'scheduler/tracing' ;
27+ import { NoPriority } from './SchedulerWithReactIntegration' ;
2628
2729// TODO: This should be lifted into the renderer.
2830export type Batch = {
@@ -69,6 +71,8 @@ type BaseFiberRootProperties = {|
6971 callbackNode : * ,
7072 // Expiration of the callback associated with this root
7173 callbackExpirationTime : ExpirationTime ,
74+ // Priority of the callback associated with this root
75+ callbackPriority : ReactPriorityLevel ,
7276 // The earliest pending expiration time that exists in the tree
7377 firstPendingTime : ExpirationTime ,
7478 // The latest pending expiration time that exists in the tree
@@ -78,7 +82,7 @@ type BaseFiberRootProperties = {|
7882 // The latest suspended expiration time that exists in the tree
7983 lastSuspendedTime : ExpirationTime ,
8084 // The next known expiration time after the suspended range
81- nextAfterSuspendedTime : ExpirationTime ,
85+ nextKnownPendingLevel : ExpirationTime ,
8286 // The latest time at which a suspended component pinged the root to
8387 // render again
8488 lastPingedTime : ExpirationTime ,
@@ -124,12 +128,12 @@ function FiberRootNode(containerInfo, tag, hydrate) {
124128 this . hydrate = hydrate ;
125129 this . firstBatch = null ;
126130 this . callbackNode = null ;
127- this . callbackExpirationTime = NoWork ;
131+ this . callbackPriority = NoPriority ;
128132 this . firstPendingTime = NoWork ;
129133 this . lastPendingTime = NoWork ;
130134 this . firstSuspendedTime = NoWork ;
131135 this . lastSuspendedTime = NoWork ;
132- this . nextAfterSuspendedTime = NoWork ;
136+ this . nextKnownPendingLevel = NoWork ;
133137 this . lastPingedTime = NoWork ;
134138
135139 if ( enableSchedulerTracing ) {
@@ -193,21 +197,66 @@ export function markRootSuspendedAtTime(
193197 }
194198}
195199
196- export function markRootUnsuspendedAtTime (
200+ export function markRootUpdatedAtTime (
197201 root : FiberRoot ,
198202 expirationTime : ExpirationTime ,
199203) : void {
200- if ( expirationTime <= root . lastSuspendedTime ) {
204+ // Update the range of pending times
205+ const firstPendingTime = root . firstPendingTime ;
206+ if ( expirationTime > firstPendingTime ) {
207+ root . firstPendingTime = expirationTime ;
208+ }
209+ const lastPendingTime = root . lastPendingTime ;
210+ if ( lastPendingTime === NoWork || expirationTime < lastPendingTime ) {
211+ root . lastPendingTime = expirationTime ;
212+ }
213+
214+ // Update the range of suspended times. Treat everything lower priority or
215+ // equal to this update as unsuspended.
216+ const firstSuspendedTime = root . firstSuspendedTime ;
217+ if ( firstSuspendedTime !== NoWork ) {
218+ if ( expirationTime >= firstSuspendedTime ) {
219+ // The entire suspended range is now unsuspended.
220+ root . firstSuspendedTime = root . lastSuspendedTime = root . nextKnownPendingLevel = NoWork ;
221+ } else if ( expirationTime >= root . lastSuspendedTime ) {
222+ root . lastSuspendedTime = expirationTime + 1 ;
223+ }
224+
225+ // This is a pending level. Check if it's higher priority than the next
226+ // known pending level.
227+ if ( expirationTime > root . nextKnownPendingLevel ) {
228+ root . nextKnownPendingLevel = expirationTime ;
229+ }
230+ }
231+ }
232+
233+ export function markRootFinishedAtTime (
234+ root : FiberRoot ,
235+ finishedExpirationTime : ExpirationTime ,
236+ remainingExpirationTime : ExpirationTime ,
237+ ) : void {
238+ // Update the range of pending times
239+ root. firstPendingTime = remainingExpirationTime ;
240+ if ( remainingExpirationTime < root . lastPendingTime ) {
241+ // This usually means we've finished all the work, but it can also happen
242+ // when something gets downprioritized during render, like a hidden tree.
243+ root . lastPendingTime = remainingExpirationTime ;
244+ }
245+
246+ // Update the range of suspended times. Treat everything higher priority or
247+ // equal to this update as unsuspended.
248+ if ( finishedExpirationTime <= root . lastSuspendedTime ) {
201249 // The entire suspended range is now unsuspended.
202- root . firstSuspendedTime = root . lastSuspendedTime = root . nextAfterSuspendedTime = NoWork ;
203- } else if ( expirationTime <= root . firstSuspendedTime ) {
250+ root . firstSuspendedTime = root . lastSuspendedTime = root . nextKnownPendingLevel = NoWork ;
251+ } else if ( finishedExpirationTime <= root . firstSuspendedTime ) {
204252 // Part of the suspended range is now unsuspended. Narrow the range to
205253 // include everything between the unsuspended time (non-inclusive) and the
206254 // last suspended time.
207- root . firstSuspendedTime = expirationTime - 1 ;
255+ root . firstSuspendedTime = finishedExpirationTime - 1 ;
208256 }
209257
210- if ( expirationTime <= root . lastPingedTime ) {
258+ if ( finishedExpirationTime <= root . lastPingedTime ) {
259+ // Clear the pinged time
211260 root . lastPingedTime = NoWork ;
212261 }
213262}
0 commit comments