@@ -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 {
@@ -308,7 +315,7 @@ function commitBeforeMutationLifeCycles(
308315 ) ;
309316}
310317
311- function commitHookEffectListUnmount ( tag : number , finishedWork : Fiber ) {
318+ function commitHookEffectListUnmount ( tag : HookEffectTag , finishedWork : Fiber ) {
312319 const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
313320 const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
314321 if ( lastEffect !== null ) {
@@ -328,7 +335,43 @@ function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {
328335 }
329336}
330337
331- function commitHookEffectListMount ( tag : number , finishedWork : Fiber ) {
338+ // TODO: Remove this duplication.
339+ function commitHookEffectListUnmount2 (
340+ // Tags to check for when deciding whether to unmount. e.g. to skip over
341+ // layout effects
342+ hookEffectTag : HookEffectTag ,
343+ fiber : Fiber ,
344+ ) : void {
345+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
346+ const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
347+ if ( lastEffect !== null ) {
348+ const firstEffect = lastEffect . next ;
349+ let effect = firstEffect ;
350+ do {
351+ const { next , tag } = effect ;
352+ if ( ( tag & hookEffectTag ) === hookEffectTag ) {
353+ const destroy = effect . destroy ;
354+ if ( destroy !== undefined ) {
355+ effect . destroy = undefined ;
356+ if (
357+ enableProfilerTimer &&
358+ enableProfilerCommitHooks &&
359+ fiber . mode & ProfileMode
360+ ) {
361+ startPassiveEffectTimer ( ) ;
362+ safelyCallDestroy ( fiber , destroy ) ;
363+ recordPassiveEffectDuration ( fiber ) ;
364+ } else {
365+ safelyCallDestroy ( fiber , destroy ) ;
366+ }
367+ }
368+ }
369+ effect = next ;
370+ } while ( effect !== firstEffect ) ;
371+ }
372+ }
373+
374+ function commitHookEffectListMount ( tag : HookEffectTag , finishedWork : Fiber ) {
332375 const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
333376 const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
334377 if ( lastEffect !== null ) {
@@ -378,6 +421,83 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
378421 }
379422}
380423
424+ function invokePassiveEffectCreate ( effect : HookEffect ) : void {
425+ const create = effect . create ;
426+ effect . destroy = create ( ) ;
427+ }
428+
429+ // TODO: Remove this duplication.
430+ function commitHookEffectListMount2 ( fiber : Fiber ) : void {
431+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
432+ const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
433+ if ( lastEffect !== null ) {
434+ const firstEffect = lastEffect . next ;
435+ let effect = firstEffect ;
436+ do {
437+ const { next , tag } = effect ;
438+
439+ if (
440+ ( tag & HookPassive ) !== NoHookEffect &&
441+ ( tag & HookHasEffect ) !== NoHookEffect
442+ ) {
443+ if ( __DEV__ ) {
444+ if (
445+ enableProfilerTimer &&
446+ enableProfilerCommitHooks &&
447+ fiber . mode & ProfileMode
448+ ) {
449+ startPassiveEffectTimer ( ) ;
450+ invokeGuardedCallback (
451+ null ,
452+ invokePassiveEffectCreate ,
453+ null ,
454+ effect ,
455+ ) ;
456+ recordPassiveEffectDuration ( fiber ) ;
457+ } else {
458+ invokeGuardedCallback (
459+ null ,
460+ invokePassiveEffectCreate ,
461+ null ,
462+ effect ,
463+ ) ;
464+ }
465+ if ( hasCaughtError ( ) ) {
466+ invariant ( fiber !== null , 'Should be working on an effect.' ) ;
467+ const error = clearCaughtError ( ) ;
468+ captureCommitPhaseError ( fiber , error ) ;
469+ }
470+ } else {
471+ try {
472+ const create = effect . create ;
473+ if (
474+ enableProfilerTimer &&
475+ enableProfilerCommitHooks &&
476+ fiber . mode & ProfileMode
477+ ) {
478+ try {
479+ startPassiveEffectTimer ( ) ;
480+ effect . destroy = create ( ) ;
481+ } finally {
482+ recordPassiveEffectDuration ( fiber ) ;
483+ }
484+ } else {
485+ effect . destroy = create ( ) ;
486+ }
487+ // TODO: This is missing the warning that exists in commitHookEffectListMount.
488+ // The warning refers to useEffect but only applies to useLayoutEffect.
489+ } catch ( error ) {
490+ invariant ( fiber !== null , 'Should be working on an effect.' ) ;
491+ captureCommitPhaseError ( fiber , error ) ;
492+ }
493+ }
494+ }
495+
496+ effect = next ;
497+ } while ( effect !== firstEffect ) ;
498+ }
499+ }
500+
381501export function commitPassiveEffectDurations (
382502 finishedRoot : FiberRoot ,
383503 finishedWork : Fiber ,
@@ -1709,13 +1829,45 @@ export function isSuspenseBoundaryBeingHidden(
17091829 return false ;
17101830}
17111831
1712- function commitResetTextContent ( current : Fiber ) {
1832+ function commitResetTextContent ( current : Fiber ) : void {
17131833 if ( ! supportsMutation ) {
17141834 return ;
17151835 }
17161836 resetTextContent ( current . stateNode ) ;
17171837}
17181838
1839+ function commitPassiveWork ( finishedWork : Fiber ) : void {
1840+ switch ( finishedWork . tag ) {
1841+ case FunctionComponent :
1842+ case ForwardRef :
1843+ case SimpleMemoComponent :
1844+ case Block : {
1845+ commitHookEffectListUnmount2 ( HookPassive | HookHasEffect , finishedWork ) ;
1846+ }
1847+ }
1848+ }
1849+
1850+ function commitPassiveUnmount ( current : Fiber ) : void {
1851+ switch ( current . tag ) {
1852+ case FunctionComponent :
1853+ case ForwardRef :
1854+ case SimpleMemoComponent :
1855+ case Block :
1856+ commitHookEffectListUnmount2 ( HookPassive , current ) ;
1857+ }
1858+ }
1859+
1860+ function commitPassiveLifeCycles ( finishedWork : Fiber ) : void {
1861+ switch ( finishedWork . tag ) {
1862+ case FunctionComponent :
1863+ case ForwardRef :
1864+ case SimpleMemoComponent :
1865+ case Block : {
1866+ commitHookEffectListMount2 ( finishedWork ) ;
1867+ }
1868+ }
1869+ }
1870+
17191871export {
17201872 commitBeforeMutationLifeCycles ,
17211873 commitResetTextContent ,
@@ -1725,4 +1877,7 @@ export {
17251877 commitLifeCycles ,
17261878 commitAttachRef ,
17271879 commitDetachRef ,
1880+ commitPassiveUnmount ,
1881+ commitPassiveWork ,
1882+ commitPassiveLifeCycles ,
17281883} ;
0 commit comments