@@ -20,10 +20,14 @@ import type {FiberRoot} from './ReactInternalTypes';
2020import type { Lanes } from './ReactFiberLane' ;
2121import type { SuspenseState } from './ReactFiberSuspenseComponent.new' ;
2222import type { UpdateQueue } from './ReactUpdateQueue.new' ;
23- import type { FunctionComponentUpdateQueue } from './ReactFiberHooks.new' ;
23+ import type {
24+ Effect as HookEffect ,
25+ FunctionComponentUpdateQueue ,
26+ } from './ReactFiberHooks.new' ;
2427import type { Wakeable } from 'shared/ReactTypes' ;
2528import type { ReactPriorityLevel } from './ReactInternalTypes' ;
2629import type { OffscreenState } from './ReactFiberOffscreenComponent' ;
30+ import type { HookEffectTag } from './ReactHookEffectTags' ;
2731
2832import { unstable_wrap as Schedule_tracing_wrap } from 'scheduler/tracing' ;
2933import {
@@ -77,6 +81,8 @@ import {
7781 getCommitTime ,
7882 recordLayoutEffectDuration ,
7983 startLayoutEffectTimer ,
84+ recordPassiveEffectDuration ,
85+ startPassiveEffectTimer ,
8086} from './ReactProfilerTimer.new' ;
8187import { ProfileMode } from './ReactTypeOfMode' ;
8288import { commitUpdateQueue } from './ReactUpdateQueue.new' ;
@@ -121,6 +127,7 @@ import {
121127 NoEffect as NoHookEffect ,
122128 HasEffect as HookHasEffect ,
123129 Layout as HookLayout ,
130+ Passive as HookPassive ,
124131} from './ReactHookEffectTags' ;
125132import { didWarnAboutReassigningProps } from './ReactFiberBeginWork.new' ;
126133import {
@@ -312,7 +319,7 @@ function commitBeforeMutationLifeCycles(
312319 ) ;
313320}
314321
315- function commitHookEffectListUnmount ( tag : number , finishedWork : Fiber ) {
322+ function commitHookEffectListUnmount ( tag : HookEffectTag , finishedWork : Fiber ) {
316323 const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
317324 const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
318325 if ( lastEffect !== null ) {
@@ -332,7 +339,43 @@ function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {
332339 }
333340}
334341
335- function commitHookEffectListMount ( tag : number , finishedWork : Fiber ) {
342+ // TODO: Remove this duplication.
343+ function commitHookEffectListUnmount2 (
344+ // Tags to check for when deciding whether to unmount. e.g. to skip over layout effects
345+ hookEffectTag : HookEffectTag ,
346+ fiber : Fiber ,
347+ nearestMountedAncestor : Fiber | null ,
348+ ) : void {
349+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
350+ const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
351+ if ( lastEffect !== null ) {
352+ const firstEffect = lastEffect . next ;
353+ let effect = firstEffect ;
354+ do {
355+ const { next, tag} = effect ;
356+ if ( ( tag & hookEffectTag ) === hookEffectTag ) {
357+ const destroy = effect . destroy ;
358+ if ( destroy !== undefined ) {
359+ effect . destroy = undefined ;
360+ if (
361+ enableProfilerTimer &&
362+ enableProfilerCommitHooks &&
363+ fiber . mode & ProfileMode
364+ ) {
365+ startPassiveEffectTimer ( ) ;
366+ safelyCallDestroy ( fiber , nearestMountedAncestor , destroy ) ;
367+ recordPassiveEffectDuration ( fiber ) ;
368+ } else {
369+ safelyCallDestroy ( fiber , nearestMountedAncestor , destroy ) ;
370+ }
371+ }
372+ }
373+ effect = next ;
374+ } while ( effect !== firstEffect ) ;
375+ }
376+ }
377+
378+ function commitHookEffectListMount ( tag : HookEffectTag , finishedWork : Fiber ) {
336379 const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
337380 const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
338381 if ( lastEffect !== null ) {
@@ -382,6 +425,83 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
382425 }
383426}
384427
428+ function invokePassiveEffectCreate ( effect : HookEffect ) : void {
429+ const create = effect . create ;
430+ effect . destroy = create ( ) ;
431+ }
432+
433+ // TODO: Remove this duplication.
434+ function commitHookEffectListMount2 ( fiber : Fiber ) : void {
435+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
436+ const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
437+ if ( lastEffect !== null ) {
438+ const firstEffect = lastEffect . next ;
439+ let effect = firstEffect ;
440+ do {
441+ const { next, tag} = effect ;
442+
443+ if (
444+ ( tag & HookPassive ) !== NoHookEffect &&
445+ ( tag & HookHasEffect ) !== NoHookEffect
446+ ) {
447+ if ( __DEV__ ) {
448+ if (
449+ enableProfilerTimer &&
450+ enableProfilerCommitHooks &&
451+ fiber . mode & ProfileMode
452+ ) {
453+ startPassiveEffectTimer ( ) ;
454+ invokeGuardedCallback (
455+ null ,
456+ invokePassiveEffectCreate ,
457+ null ,
458+ effect ,
459+ ) ;
460+ recordPassiveEffectDuration ( fiber ) ;
461+ } else {
462+ invokeGuardedCallback (
463+ null ,
464+ invokePassiveEffectCreate ,
465+ null ,
466+ effect ,
467+ ) ;
468+ }
469+ if ( hasCaughtError ( ) ) {
470+ invariant ( fiber !== null , 'Should be working on an effect.' ) ;
471+ const error = clearCaughtError ( ) ;
472+ captureCommitPhaseError ( fiber , fiber . return , error ) ;
473+ }
474+ } else {
475+ try {
476+ const create = effect . create ;
477+ if (
478+ enableProfilerTimer &&
479+ enableProfilerCommitHooks &&
480+ fiber . mode & ProfileMode
481+ ) {
482+ try {
483+ startPassiveEffectTimer ( ) ;
484+ effect . destroy = create ( ) ;
485+ } finally {
486+ recordPassiveEffectDuration ( fiber ) ;
487+ }
488+ } else {
489+ effect . destroy = create ( ) ;
490+ }
491+ // TODO: This is missing the warning that exists in commitHookEffectListMount.
492+ // The warning refers to useEffect but only applies to useLayoutEffect.
493+ } catch ( error ) {
494+ invariant ( fiber !== null , 'Should be working on an effect.' ) ;
495+ captureCommitPhaseError ( fiber , fiber . return , error ) ;
496+ }
497+ }
498+ }
499+
500+ effect = next ;
501+ } while ( effect !== firstEffect ) ;
502+ }
503+ }
504+
385505export function commitPassiveEffectDurations (
386506 finishedRoot : FiberRoot ,
387507 finishedWork : Fiber ,
@@ -1713,13 +1833,56 @@ export function isSuspenseBoundaryBeingHidden(
17131833 return false ;
17141834}
17151835
1716- function commitResetTextContent ( current : Fiber ) {
1836+ function commitResetTextContent ( current : Fiber ) : void {
17171837 if ( ! supportsMutation ) {
17181838 return ;
17191839 }
17201840 resetTextContent ( current . stateNode ) ;
17211841}
17221842
1843+ function commitPassiveWork ( finishedWork : Fiber ) : void {
1844+ switch ( finishedWork . tag ) {
1845+ case FunctionComponent :
1846+ case ForwardRef :
1847+ case SimpleMemoComponent :
1848+ case Block : {
1849+ commitHookEffectListUnmount2 (
1850+ HookPassive | HookHasEffect ,
1851+ finishedWork ,
1852+ finishedWork . return ,
1853+ ) ;
1854+ }
1855+ }
1856+ }
1857+
1858+ function commitPassiveUnmount (
1859+ current : Fiber ,
1860+ nearestMountedAncestor : Fiber | null ,
1861+ ) : void {
1862+ switch ( current . tag ) {
1863+ case FunctionComponent :
1864+ case ForwardRef :
1865+ case SimpleMemoComponent :
1866+ case Block :
1867+ commitHookEffectListUnmount2 (
1868+ HookPassive ,
1869+ current ,
1870+ nearestMountedAncestor ,
1871+ ) ;
1872+ }
1873+ }
1874+
1875+ function commitPassiveLifeCycles ( finishedWork : Fiber ) : void {
1876+ switch ( finishedWork . tag ) {
1877+ case FunctionComponent :
1878+ case ForwardRef :
1879+ case SimpleMemoComponent :
1880+ case Block : {
1881+ commitHookEffectListMount2 ( finishedWork ) ;
1882+ }
1883+ }
1884+ }
1885+
17231886export {
17241887 commitBeforeMutationLifeCycles ,
17251888 commitResetTextContent ,
@@ -1729,4 +1892,7 @@ export {
17291892 commitLifeCycles ,
17301893 commitAttachRef ,
17311894 commitDetachRef ,
1895+ commitPassiveUnmount ,
1896+ commitPassiveWork ,
1897+ commitPassiveLifeCycles ,
17321898} ;
0 commit comments