@@ -75,7 +75,14 @@ import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
7575import { getStackByFiberInDevAndProd } from './ReactCurrentFiber' ;
7676import { logCapturedError } from './ReactFiberErrorLogger' ;
7777import { resolveDefaultProps } from './ReactFiberLazyComponent' ;
78- import { getCommitTime } from './ReactProfilerTimer' ;
78+ import {
79+ getCommitTime ,
80+ recordLayoutEffectDuration ,
81+ recordPassiveEffectDuration ,
82+ startLayoutEffectTimer ,
83+ startPassiveEffectTimer ,
84+ } from './ReactProfilerTimer' ;
85+ import { ProfileMode } from './ReactTypeOfMode' ;
7986import { commitUpdateQueue } from './ReactUpdateQueue' ;
8087import {
8188 getPublicInstance ,
@@ -401,11 +408,18 @@ export function commitPassiveHookEffects(finishedWork: Fiber): void {
401408 case ForwardRef :
402409 case SimpleMemoComponent :
403410 case Chunk : {
404- // TODO (#17945) We should call all passive destroy functions (for all fibers)
405- // before calling any create functions. The current approach only serializes
406- // these for a single fiber.
407- commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
408- commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
411+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
412+ try {
413+ startPassiveEffectTimer ( ) ;
414+ commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
415+ commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
416+ } finally {
417+ recordPassiveEffectDuration ( finishedWork ) ;
418+ }
419+ } else {
420+ commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
421+ commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
422+ }
409423 break ;
410424 }
411425 default :
@@ -421,7 +435,16 @@ export function commitPassiveHookUnmountEffects(finishedWork: Fiber): void {
421435 case ForwardRef :
422436 case SimpleMemoComponent :
423437 case Chunk : {
424- commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
438+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
439+ try {
440+ startPassiveEffectTimer ( ) ;
441+ commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
442+ } finally {
443+ recordPassiveEffectDuration ( finishedWork ) ;
444+ }
445+ } else {
446+ commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
447+ }
425448 break ;
426449 }
427450 default :
@@ -437,7 +460,16 @@ export function commitPassiveHookMountEffects(finishedWork: Fiber): void {
437460 case ForwardRef :
438461 case SimpleMemoComponent :
439462 case Chunk : {
440- commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
463+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
464+ try {
465+ startPassiveEffectTimer ( ) ;
466+ commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
467+ } finally {
468+ recordPassiveEffectDuration ( finishedWork ) ;
469+ }
470+ } else {
471+ commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
472+ }
441473 break ;
442474 }
443475 default :
@@ -446,6 +478,61 @@ export function commitPassiveHookMountEffects(finishedWork: Fiber): void {
446478 }
447479}
448480
481+ export function commitPassiveEffectDurations (
482+ finishedRoot : FiberRoot ,
483+ finishedWork : Fiber ,
484+ ) : void {
485+ if ( enableProfilerTimer ) {
486+ // Only Profilers with work in their subtree will have an Update effect scheduled.
487+ if ( ( finishedWork . effectTag & Update ) !== NoEffect ) {
488+ switch ( finishedWork . tag ) {
489+ case Profiler : {
490+ const { passiveEffectDuration} = finishedWork . stateNode ;
491+ const { id, onPostCommit} = finishedWork . memoizedProps ;
492+
493+ // This value will still reflect the previous commit phase.
494+ // It does not get reset until the start of the next commit phase.
495+ const commitTime = getCommitTime ( ) ;
496+
497+ if ( typeof onPostCommit === 'function' ) {
498+ if ( enableSchedulerTracing ) {
499+ onPostCommit (
500+ id ,
501+ finishedWork . alternate === null ? 'mount' : 'update' ,
502+ passiveEffectDuration ,
503+ commitTime ,
504+ finishedRoot . memoizedInteractions ,
505+ ) ;
506+ } else {
507+ onPostCommit (
508+ id ,
509+ finishedWork . alternate === null ? 'mount' : 'update' ,
510+ passiveEffectDuration ,
511+ commitTime ,
512+ ) ;
513+ }
514+ }
515+
516+ // Bubble times to the next nearest ancestor Profiler.
517+ // After we process that Profiler, we'll bubble further up.
518+ let parentFiber = finishedWork . return ;
519+ while ( parentFiber !== null ) {
520+ if ( parentFiber . tag === Profiler ) {
521+ const parentStateNode = parentFiber . stateNode ;
522+ parentStateNode . passiveEffectDuration += passiveEffectDuration ;
523+ break ;
524+ }
525+ parentFiber = parentFiber . return ;
526+ }
527+ break ;
528+ }
529+ default :
530+ break ;
531+ }
532+ }
533+ }
534+ }
535+
449536function commitLifeCycles (
450537 finishedRoot : FiberRoot ,
451538 current : Fiber | null ,
@@ -461,7 +548,16 @@ function commitLifeCycles(
461548 // This is done to prevent sibling component effects from interfering with each other,
462549 // e.g. a destroy function in one component should never override a ref set
463550 // by a create function in another component during the same commit.
464- commitHookEffectList ( NoHookEffect , HookLayout , finishedWork ) ;
551+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
552+ try {
553+ startLayoutEffectTimer ( ) ;
554+ commitHookEffectList ( NoHookEffect , HookLayout , finishedWork ) ;
555+ } finally {
556+ recordLayoutEffectDuration ( finishedWork ) ;
557+ }
558+ } else {
559+ commitHookEffectList ( NoHookEffect , HookLayout , finishedWork ) ;
560+ }
465561 return ;
466562 }
467563 case ClassComponent : {
@@ -499,7 +595,16 @@ function commitLifeCycles(
499595 }
500596 }
501597 }
502- instance . componentDidMount ( ) ;
598+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
599+ try {
600+ startLayoutEffectTimer ( ) ;
601+ instance . componentDidMount ( ) ;
602+ } finally {
603+ recordLayoutEffectDuration ( finishedWork ) ;
604+ }
605+ } else {
606+ instance . componentDidMount ( ) ;
607+ }
503608 stopPhaseTimer ( ) ;
504609 } else {
505610 const prevProps =
@@ -538,11 +643,24 @@ function commitLifeCycles(
538643 }
539644 }
540645 }
541- instance . componentDidUpdate (
542- prevProps ,
543- prevState ,
544- instance . __reactInternalSnapshotBeforeUpdate ,
545- ) ;
646+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
647+ try {
648+ startLayoutEffectTimer ( ) ;
649+ instance . componentDidUpdate (
650+ prevProps ,
651+ prevState ,
652+ instance . __reactInternalSnapshotBeforeUpdate ,
653+ ) ;
654+ } finally {
655+ recordLayoutEffectDuration ( finishedWork ) ;
656+ }
657+ } else {
658+ instance . componentDidUpdate (
659+ prevProps ,
660+ prevState ,
661+ instance . __reactInternalSnapshotBeforeUpdate ,
662+ ) ;
663+ }
546664 stopPhaseTimer ( ) ;
547665 }
548666 }
@@ -635,7 +753,10 @@ function commitLifeCycles(
635753 }
636754 case Profiler : {
637755 if ( enableProfilerTimer ) {
638- const onRender = finishedWork . memoizedProps . onRender ;
756+ const { onCommit, onRender} = finishedWork . memoizedProps ;
757+ const { effectDuration} = finishedWork . stateNode ;
758+
759+ const commitTime = getCommitTime ( ) ;
639760
640761 if ( typeof onRender === 'function' ) {
641762 if ( enableSchedulerTracing ) {
@@ -645,7 +766,7 @@ function commitLifeCycles(
645766 finishedWork . actualDuration ,
646767 finishedWork . treeBaseDuration ,
647768 finishedWork . actualStartTime ,
648- getCommitTime ( ) ,
769+ commitTime ,
649770 finishedRoot . memoizedInteractions ,
650771 ) ;
651772 } else {
@@ -655,10 +776,41 @@ function commitLifeCycles(
655776 finishedWork . actualDuration ,
656777 finishedWork . treeBaseDuration ,
657778 finishedWork . actualStartTime ,
658- getCommitTime ( ) ,
779+ commitTime ,
780+ ) ;
781+ }
782+ }
783+
784+ if ( typeof onCommit === 'function' ) {
785+ if ( enableSchedulerTracing ) {
786+ onCommit (
787+ finishedWork . memoizedProps . id ,
788+ current === null ? 'mount' : 'update' ,
789+ effectDuration ,
790+ commitTime ,
791+ finishedRoot . memoizedInteractions ,
792+ ) ;
793+ } else {
794+ onCommit (
795+ finishedWork . memoizedProps . id ,
796+ current === null ? 'mount' : 'update' ,
797+ effectDuration ,
798+ commitTime ,
659799 ) ;
660800 }
661801 }
802+
803+ // Propagate layout effect durations to the next nearest Profiler ancestor.
804+ // Do not reset these values until the next render so DevTools has a chance to read them first.
805+ let parentFiber = finishedWork . return ;
806+ while ( parentFiber !== null ) {
807+ if ( parentFiber . tag === Profiler ) {
808+ const parentStateNode = parentFiber . stateNode ;
809+ parentStateNode . effectDuration += effectDuration ;
810+ break ;
811+ }
812+ parentFiber = parentFiber . return ;
813+ }
662814 }
663815 return ;
664816 }
@@ -806,7 +958,13 @@ function commitUnmount(
806958 if ( ( tag & HookPassive ) !== NoHookEffect ) {
807959 enqueuePendingPassiveEffectDestroyFn ( destroy ) ;
808960 } else {
809- safelyCallDestroy ( current , destroy ) ;
961+ if ( enableProfilerTimer && current . mode & ProfileMode ) {
962+ startLayoutEffectTimer ( ) ;
963+ safelyCallDestroy ( current , destroy ) ;
964+ recordLayoutEffectDuration ( current ) ;
965+ } else {
966+ safelyCallDestroy ( current , destroy ) ;
967+ }
810968 }
811969 }
812970 effect = effect . next ;
@@ -847,7 +1005,13 @@ function commitUnmount(
8471005 safelyDetachRef ( current ) ;
8481006 const instance = current . stateNode ;
8491007 if ( typeof instance . componentWillUnmount === 'function' ) {
850- safelyCallComponentWillUnmount ( current , instance ) ;
1008+ if ( enableProfilerTimer && current . mode & ProfileMode ) {
1009+ startLayoutEffectTimer ( ) ;
1010+ safelyCallComponentWillUnmount ( current , instance ) ;
1011+ recordLayoutEffectDuration ( current ) ;
1012+ } else {
1013+ safelyCallComponentWillUnmount ( current , instance ) ;
1014+ }
8511015 }
8521016 return ;
8531017 }
@@ -1347,7 +1511,16 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13471511 // This prevents sibling component effects from interfering with each other,
13481512 // e.g. a destroy function in one component should never override a ref set
13491513 // by a create function in another component during the same commit.
1350- commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1514+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
1515+ try {
1516+ startLayoutEffectTimer ( ) ;
1517+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1518+ } finally {
1519+ recordLayoutEffectDuration ( finishedWork ) ;
1520+ }
1521+ } else {
1522+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1523+ }
13511524 return ;
13521525 }
13531526 case Profiler : {
@@ -1390,7 +1563,16 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13901563 // This prevents sibling component effects from interfering with each other,
13911564 // e.g. a destroy function in one component should never override a ref set
13921565 // by a create function in another component during the same commit.
1393- commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1566+ if ( enableProfilerTimer && finishedWork . mode & ProfileMode ) {
1567+ try {
1568+ startLayoutEffectTimer ( ) ;
1569+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1570+ } finally {
1571+ recordLayoutEffectDuration ( finishedWork ) ;
1572+ }
1573+ } else {
1574+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
1575+ }
13941576 return ;
13951577 }
13961578 case ClassComponent : {
0 commit comments