@@ -341,7 +341,6 @@ let hasUncaughtError = false;
341341let firstUncaughtError = null;
342342let legacyErrorBoundariesThatAlreadyFailed: Set< mixed > | null = null;
343343
344- let rootDoesHavePassiveEffects: boolean = false;
345344let rootWithPendingPassiveEffects: FiberRoot | null = null;
346345let pendingPassiveEffectsRenderPriority: ReactPriorityLevel = NoSchedulerPriority;
347346let pendingPassiveEffectsLanes: Lanes = NoLanes;
@@ -1865,6 +1864,22 @@ function commitRootImpl(root, renderPriorityLevel) {
18651864 // times out.
18661865 }
18671866
1867+ // If there are pending passive effects, schedule a callback to process them.
1868+ // Do this as early as possible, so it is queued before anything else that
1869+ // might get scheduled in the commit phase. (See #16714.)
1870+ const rootDoesHavePassiveEffects =
1871+ ( finishedWork . subtreeFlags & PassiveMask ) !== NoFlags ||
1872+ ( finishedWork . flags & PassiveMask ) !== NoFlags ;
1873+ if ( rootDoesHavePassiveEffects ) {
1874+ rootWithPendingPassiveEffects = root ;
1875+ pendingPassiveEffectsLanes = lanes ;
1876+ pendingPassiveEffectsRenderPriority = renderPriorityLevel ;
1877+ scheduleCallback ( NormalSchedulerPriority , ( ) => {
1878+ flushPassiveEffects ( ) ;
1879+ return null ;
1880+ } ) ;
1881+ }
1882+
18681883 // Check if there are any effects in the whole tree.
18691884 // TODO: This is left over from the effect list implementation, where we had
18701885 // to check for the existence of `firstEffect` to satsify Flow. I think the
@@ -1880,20 +1895,6 @@ function commitRootImpl(root, renderPriorityLevel) {
18801895 NoFlags ;
18811896
18821897 if ( subtreeHasEffects || rootHasEffect ) {
1883- // If there are pending passive effects, schedule a callback to process them.
1884- if (
1885- ( finishedWork . subtreeFlags & PassiveMask ) !== NoFlags ||
1886- ( finishedWork . flags & PassiveMask ) !== NoFlags
1887- ) {
1888- if ( ! rootDoesHavePassiveEffects ) {
1889- rootDoesHavePassiveEffects = true ;
1890- scheduleCallback ( NormalSchedulerPriority , ( ) => {
1891- flushPassiveEffects ( ) ;
1892- return null ;
1893- } ) ;
1894- }
1895- }
1896-
18971898 let previousLanePriority ;
18981899 if ( decoupleUpdatePriorityFromScheduler ) {
18991900 previousLanePriority = getCurrentUpdateLanePriority ( ) ;
@@ -2010,17 +2011,6 @@ function commitRootImpl(root, renderPriorityLevel) {
20102011 }
20112012 }
20122013
2013- const rootDidHavePassiveEffects = rootDoesHavePassiveEffects ;
2014-
2015- if ( rootDoesHavePassiveEffects ) {
2016- // This commit has passive effects. Stash a reference to them. But don't
2017- // schedule a callback until after flushing layout work.
2018- rootDoesHavePassiveEffects = false ;
2019- rootWithPendingPassiveEffects = root ;
2020- pendingPassiveEffectsLanes = lanes ;
2021- pendingPassiveEffectsRenderPriority = renderPriorityLevel ;
2022- }
2023-
20242014 // Read this again, since an effect might have updated it
20252015 remainingLanes = root . pendingLanes ;
20262016
@@ -2047,13 +2037,13 @@ function commitRootImpl(root, renderPriorityLevel) {
20472037 }
20482038
20492039 if ( __DEV__ && enableDoubleInvokingEffects ) {
2050- if ( ! rootDidHavePassiveEffects ) {
2040+ if ( ! rootDoesHavePassiveEffects ) {
20512041 commitDoubleInvokeEffectsInDEV ( root . current , false ) ;
20522042 }
20532043 }
20542044
20552045 if ( enableSchedulerTracing ) {
2056- if ( ! rootDidHavePassiveEffects ) {
2046+ if ( ! rootDoesHavePassiveEffects ) {
20572047 // If there are no passive effects, then we can complete the pending interactions.
20582048 // Otherwise, we'll wait until after the passive effects are flushed.
20592049 // Wait to do this until after remaining work has been scheduled,
@@ -2356,16 +2346,6 @@ function commitMutationEffectsDeletions(
23562346 }
23572347}
23582348
2359- export function schedulePassiveEffectCallback ( ) {
2360- if ( ! rootDoesHavePassiveEffects ) {
2361- rootDoesHavePassiveEffects = true ;
2362- scheduleCallback ( NormalSchedulerPriority , ( ) => {
2363- flushPassiveEffects ( ) ;
2364- return null ;
2365- } ) ;
2366- }
2367- }
2368-
23692349export function flushPassiveEffects ( ) : boolean {
23702350 // Returns whether passive effects were flushed.
23712351 if ( pendingPassiveEffectsRenderPriority !== NoSchedulerPriority ) {
0 commit comments