mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Extract layout effects to separate functions
There's a lot of duplicated code between commitLayoutEffectOnFiber and the "reappear layout effects" path that happens when an Offscreen tree goes from hidden back to visible. I'm going to refactor these to share more of the same code. As a first step, this extracts the shared parts into separate functions. This may not save much on code size because Closure will likely inline some of it, anyway, but it makes it harder for the two paths to accidentally diverge.
This commit is contained in:
@@ -706,6 +706,272 @@ export function commitPassiveEffectDurations(
|
||||
}
|
||||
}
|
||||
|
||||
function commitHookLayoutEffects(finishedWork: Fiber) {
|
||||
// At this point layout effects have already been destroyed (during mutation phase).
|
||||
// This is done to prevent sibling component effects from interfering with each other,
|
||||
// e.g. a destroy function in one component should never override a ref set
|
||||
// by a create function in another component during the same commit.
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitClassLayoutLifecycles(
|
||||
finishedWork: Fiber,
|
||||
current: Fiber | null,
|
||||
) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (current === null) {
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const prevProps =
|
||||
finishedWork.elementType === finishedWork.type
|
||||
? current.memoizedProps
|
||||
: resolveDefaultProps(finishedWork.type, current.memoizedProps);
|
||||
const prevState = current.memoizedState;
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitClassCallbacks(finishedWork: Fiber, current: Fiber | null) {
|
||||
// TODO: I think this is now always non-null by the time it reaches the
|
||||
// commit phase. Consider removing the type check.
|
||||
const updateQueue: UpdateQueue<*> | null = (finishedWork.updateQueue: any);
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
try {
|
||||
commitCallbacks(updateQueue, instance);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitHostComponentMount(finishedWork: Fiber, current: Fiber | null) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
const instance: Instance = finishedWork.stateNode;
|
||||
try {
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
|
||||
function commitProfilerUpdate(finishedWork: Fiber, current: Fiber | null) {
|
||||
if (enableProfilerTimer) {
|
||||
try {
|
||||
const {onCommit, onRender} = finishedWork.memoizedProps;
|
||||
const {effectDuration} = finishedWork.stateNode;
|
||||
|
||||
const commitTime = getCommitTime();
|
||||
|
||||
let phase = current === null ? 'mount' : 'update';
|
||||
if (enableProfilerNestedUpdatePhase) {
|
||||
if (isCurrentUpdateNested()) {
|
||||
phase = 'nested-update';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
// Schedule a passive effect for this Profiler to call onPostCommit hooks.
|
||||
// This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
|
||||
// because the effect is also where times bubble to parent Profilers.
|
||||
enqueuePendingPassiveProfilerEffect(finishedWork);
|
||||
|
||||
// Propagate layout effect durations to the next nearest Profiler ancestor.
|
||||
// Do not reset these values until the next render so DevTools has a chance to read them first.
|
||||
let parentFiber = finishedWork.return;
|
||||
outer: while (parentFiber !== null) {
|
||||
switch (parentFiber.tag) {
|
||||
case HostRoot:
|
||||
const root = parentFiber.stateNode;
|
||||
root.effectDuration += effectDuration;
|
||||
break outer;
|
||||
case Profiler:
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break outer;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitLayoutEffectOnFiber(
|
||||
finishedRoot: FiberRoot,
|
||||
current: Fiber | null,
|
||||
@@ -724,35 +990,7 @@ function commitLayoutEffectOnFiber(
|
||||
);
|
||||
if (flags & Update) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
// At this point layout effects have already been destroyed (during mutation phase).
|
||||
// This is done to prevent sibling component effects from interfering with each other,
|
||||
// e.g. a destroy function in one component should never override a ref set
|
||||
// by a create function in another component during the same commit.
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
commitHookEffectListMount(
|
||||
HookLayout | HookHasEffect,
|
||||
finishedWork,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
commitHookEffectListMount(
|
||||
HookLayout | HookHasEffect,
|
||||
finishedWork,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
commitHookLayoutEffects(finishedWork);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -765,193 +1003,17 @@ function commitLayoutEffectOnFiber(
|
||||
);
|
||||
if (flags & Update) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (current === null) {
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const prevProps =
|
||||
finishedWork.elementType === finishedWork.type
|
||||
? current.memoizedProps
|
||||
: resolveDefaultProps(finishedWork.type, current.memoizedProps);
|
||||
const prevState = current.memoizedState;
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
commitClassLayoutLifecycles(finishedWork, current);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & Callback) {
|
||||
// TODO: I think this is now always non-null by the time it reaches the
|
||||
// commit phase. Consider removing the type check.
|
||||
const updateQueue: UpdateQueue<
|
||||
*,
|
||||
> | null = (finishedWork.updateQueue: any);
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
try {
|
||||
commitCallbacks(updateQueue, instance);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
commitClassCallbacks(finishedWork, current);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
try {
|
||||
commitAttachRef(finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
safelyAttachRef(finishedWork, finishedWork.return);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -995,31 +1057,18 @@ function commitLayoutEffectOnFiber(
|
||||
finishedWork,
|
||||
committedLanes,
|
||||
);
|
||||
if (flags & Update) {
|
||||
const instance: Instance = finishedWork.stateNode;
|
||||
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && finishedWork.flags & Update) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
try {
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && flags & Update) {
|
||||
commitHostComponentMount(finishedWork, current);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
try {
|
||||
commitAttachRef(finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
safelyAttachRef(finishedWork, finishedWork.return);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1030,68 +1079,10 @@ function commitLayoutEffectOnFiber(
|
||||
finishedWork,
|
||||
committedLanes,
|
||||
);
|
||||
if (enableProfilerTimer) {
|
||||
if (flags & Update) {
|
||||
try {
|
||||
const {onCommit, onRender} = finishedWork.memoizedProps;
|
||||
const {effectDuration} = finishedWork.stateNode;
|
||||
|
||||
const commitTime = getCommitTime();
|
||||
|
||||
let phase = current === null ? 'mount' : 'update';
|
||||
if (enableProfilerNestedUpdatePhase) {
|
||||
if (isCurrentUpdateNested()) {
|
||||
phase = 'nested-update';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
// Schedule a passive effect for this Profiler to call onPostCommit hooks.
|
||||
// This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
|
||||
// because the effect is also where times bubble to parent Profilers.
|
||||
enqueuePendingPassiveProfilerEffect(finishedWork);
|
||||
|
||||
// Propagate layout effect durations to the next nearest Profiler ancestor.
|
||||
// Do not reset these values until the next render so DevTools has a chance to read them first.
|
||||
let parentFiber = finishedWork.return;
|
||||
outer: while (parentFiber !== null) {
|
||||
switch (parentFiber.tag) {
|
||||
case HostRoot:
|
||||
const root = parentFiber.stateNode;
|
||||
root.effectDuration += effectDuration;
|
||||
break outer;
|
||||
case Profiler:
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break outer;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
// TODO: Should this fire inside an offscreen tree? Or should it wait to
|
||||
// fire when the tree becomes visible again.
|
||||
if (flags & Update) {
|
||||
commitProfilerUpdate(finishedWork, current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1102,11 +1093,7 @@ function commitLayoutEffectOnFiber(
|
||||
committedLanes,
|
||||
);
|
||||
if (flags & Update) {
|
||||
try {
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2079,15 +2066,19 @@ function commitSuspenseHydrationCallbacks(
|
||||
if (prevState !== null) {
|
||||
const suspenseInstance = prevState.dehydrated;
|
||||
if (suspenseInstance !== null) {
|
||||
commitHydratedSuspenseInstance(suspenseInstance);
|
||||
if (enableSuspenseCallback) {
|
||||
const hydrationCallbacks = finishedRoot.hydrationCallbacks;
|
||||
if (hydrationCallbacks !== null) {
|
||||
const onHydrated = hydrationCallbacks.onHydrated;
|
||||
if (onHydrated) {
|
||||
onHydrated(suspenseInstance);
|
||||
try {
|
||||
commitHydratedSuspenseInstance(suspenseInstance);
|
||||
if (enableSuspenseCallback) {
|
||||
const hydrationCallbacks = finishedRoot.hydrationCallbacks;
|
||||
if (hydrationCallbacks !== null) {
|
||||
const onHydrated = hydrationCallbacks.onHydrated;
|
||||
if (onHydrated) {
|
||||
onHydrated(suspenseInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,6 +706,272 @@ export function commitPassiveEffectDurations(
|
||||
}
|
||||
}
|
||||
|
||||
function commitHookLayoutEffects(finishedWork: Fiber) {
|
||||
// At this point layout effects have already been destroyed (during mutation phase).
|
||||
// This is done to prevent sibling component effects from interfering with each other,
|
||||
// e.g. a destroy function in one component should never override a ref set
|
||||
// by a create function in another component during the same commit.
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitClassLayoutLifecycles(
|
||||
finishedWork: Fiber,
|
||||
current: Fiber | null,
|
||||
) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (current === null) {
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const prevProps =
|
||||
finishedWork.elementType === finishedWork.type
|
||||
? current.memoizedProps
|
||||
: resolveDefaultProps(finishedWork.type, current.memoizedProps);
|
||||
const prevState = current.memoizedState;
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitClassCallbacks(finishedWork: Fiber, current: Fiber | null) {
|
||||
// TODO: I think this is now always non-null by the time it reaches the
|
||||
// commit phase. Consider removing the type check.
|
||||
const updateQueue: UpdateQueue<*> | null = (finishedWork.updateQueue: any);
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
try {
|
||||
commitCallbacks(updateQueue, instance);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitHostComponentMount(finishedWork: Fiber, current: Fiber | null) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
const instance: Instance = finishedWork.stateNode;
|
||||
try {
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
|
||||
function commitProfilerUpdate(finishedWork: Fiber, current: Fiber | null) {
|
||||
if (enableProfilerTimer) {
|
||||
try {
|
||||
const {onCommit, onRender} = finishedWork.memoizedProps;
|
||||
const {effectDuration} = finishedWork.stateNode;
|
||||
|
||||
const commitTime = getCommitTime();
|
||||
|
||||
let phase = current === null ? 'mount' : 'update';
|
||||
if (enableProfilerNestedUpdatePhase) {
|
||||
if (isCurrentUpdateNested()) {
|
||||
phase = 'nested-update';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
// Schedule a passive effect for this Profiler to call onPostCommit hooks.
|
||||
// This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
|
||||
// because the effect is also where times bubble to parent Profilers.
|
||||
enqueuePendingPassiveProfilerEffect(finishedWork);
|
||||
|
||||
// Propagate layout effect durations to the next nearest Profiler ancestor.
|
||||
// Do not reset these values until the next render so DevTools has a chance to read them first.
|
||||
let parentFiber = finishedWork.return;
|
||||
outer: while (parentFiber !== null) {
|
||||
switch (parentFiber.tag) {
|
||||
case HostRoot:
|
||||
const root = parentFiber.stateNode;
|
||||
root.effectDuration += effectDuration;
|
||||
break outer;
|
||||
case Profiler:
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break outer;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitLayoutEffectOnFiber(
|
||||
finishedRoot: FiberRoot,
|
||||
current: Fiber | null,
|
||||
@@ -724,35 +990,7 @@ function commitLayoutEffectOnFiber(
|
||||
);
|
||||
if (flags & Update) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
// At this point layout effects have already been destroyed (during mutation phase).
|
||||
// This is done to prevent sibling component effects from interfering with each other,
|
||||
// e.g. a destroy function in one component should never override a ref set
|
||||
// by a create function in another component during the same commit.
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
commitHookEffectListMount(
|
||||
HookLayout | HookHasEffect,
|
||||
finishedWork,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
commitHookEffectListMount(
|
||||
HookLayout | HookHasEffect,
|
||||
finishedWork,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
commitHookLayoutEffects(finishedWork);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -765,193 +1003,17 @@ function commitLayoutEffectOnFiber(
|
||||
);
|
||||
if (flags & Update) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (current === null) {
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidMount. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidMount();
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const prevProps =
|
||||
finishedWork.elementType === finishedWork.type
|
||||
? current.memoizedProps
|
||||
: resolveDefaultProps(finishedWork.type, current.memoizedProps);
|
||||
const prevState = current.memoizedState;
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'componentDidUpdate. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
} else {
|
||||
try {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(
|
||||
finishedWork,
|
||||
finishedWork.return,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
commitClassLayoutLifecycles(finishedWork, current);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & Callback) {
|
||||
// TODO: I think this is now always non-null by the time it reaches the
|
||||
// commit phase. Consider removing the type check.
|
||||
const updateQueue: UpdateQueue<
|
||||
*,
|
||||
> | null = (finishedWork.updateQueue: any);
|
||||
if (updateQueue !== null) {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
finishedWork.type === finishedWork.elementType &&
|
||||
!didWarnAboutReassigningProps
|
||||
) {
|
||||
if (instance.props !== finishedWork.memoizedProps) {
|
||||
console.error(
|
||||
'Expected %s props to match memoized props before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.props`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
if (instance.state !== finishedWork.memoizedState) {
|
||||
console.error(
|
||||
'Expected %s state to match memoized state before ' +
|
||||
'processing the update queue. ' +
|
||||
'This might either be because of a bug in React, or because ' +
|
||||
'a component reassigns its own `this.state`. ' +
|
||||
'Please file an issue.',
|
||||
getComponentNameFromFiber(finishedWork) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could update instance props and state here,
|
||||
// but instead we rely on them being set during last render.
|
||||
// TODO: revisit this when we implement resuming.
|
||||
try {
|
||||
commitCallbacks(updateQueue, instance);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
commitClassCallbacks(finishedWork, current);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
try {
|
||||
commitAttachRef(finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
safelyAttachRef(finishedWork, finishedWork.return);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -995,31 +1057,18 @@ function commitLayoutEffectOnFiber(
|
||||
finishedWork,
|
||||
committedLanes,
|
||||
);
|
||||
if (flags & Update) {
|
||||
const instance: Instance = finishedWork.stateNode;
|
||||
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && finishedWork.flags & Update) {
|
||||
const type = finishedWork.type;
|
||||
const props = finishedWork.memoizedProps;
|
||||
try {
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
// Renderers may schedule work to be done after host components are mounted
|
||||
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
|
||||
// These effects should only be committed when components are first mounted,
|
||||
// aka when there is no current/alternate.
|
||||
if (current === null && flags & Update) {
|
||||
commitHostComponentMount(finishedWork, current);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
if (!offscreenSubtreeWasHidden) {
|
||||
try {
|
||||
commitAttachRef(finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
safelyAttachRef(finishedWork, finishedWork.return);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1030,68 +1079,10 @@ function commitLayoutEffectOnFiber(
|
||||
finishedWork,
|
||||
committedLanes,
|
||||
);
|
||||
if (enableProfilerTimer) {
|
||||
if (flags & Update) {
|
||||
try {
|
||||
const {onCommit, onRender} = finishedWork.memoizedProps;
|
||||
const {effectDuration} = finishedWork.stateNode;
|
||||
|
||||
const commitTime = getCommitTime();
|
||||
|
||||
let phase = current === null ? 'mount' : 'update';
|
||||
if (enableProfilerNestedUpdatePhase) {
|
||||
if (isCurrentUpdateNested()) {
|
||||
phase = 'nested-update';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
|
||||
// Schedule a passive effect for this Profiler to call onPostCommit hooks.
|
||||
// This effect should be scheduled even if there is no onPostCommit callback for this Profiler,
|
||||
// because the effect is also where times bubble to parent Profilers.
|
||||
enqueuePendingPassiveProfilerEffect(finishedWork);
|
||||
|
||||
// Propagate layout effect durations to the next nearest Profiler ancestor.
|
||||
// Do not reset these values until the next render so DevTools has a chance to read them first.
|
||||
let parentFiber = finishedWork.return;
|
||||
outer: while (parentFiber !== null) {
|
||||
switch (parentFiber.tag) {
|
||||
case HostRoot:
|
||||
const root = parentFiber.stateNode;
|
||||
root.effectDuration += effectDuration;
|
||||
break outer;
|
||||
case Profiler:
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break outer;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
// TODO: Should this fire inside an offscreen tree? Or should it wait to
|
||||
// fire when the tree becomes visible again.
|
||||
if (flags & Update) {
|
||||
commitProfilerUpdate(finishedWork, current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1102,11 +1093,7 @@ function commitLayoutEffectOnFiber(
|
||||
committedLanes,
|
||||
);
|
||||
if (flags & Update) {
|
||||
try {
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2079,15 +2066,19 @@ function commitSuspenseHydrationCallbacks(
|
||||
if (prevState !== null) {
|
||||
const suspenseInstance = prevState.dehydrated;
|
||||
if (suspenseInstance !== null) {
|
||||
commitHydratedSuspenseInstance(suspenseInstance);
|
||||
if (enableSuspenseCallback) {
|
||||
const hydrationCallbacks = finishedRoot.hydrationCallbacks;
|
||||
if (hydrationCallbacks !== null) {
|
||||
const onHydrated = hydrationCallbacks.onHydrated;
|
||||
if (onHydrated) {
|
||||
onHydrated(suspenseInstance);
|
||||
try {
|
||||
commitHydratedSuspenseInstance(suspenseInstance);
|
||||
if (enableSuspenseCallback) {
|
||||
const hydrationCallbacks = finishedRoot.hydrationCallbacks;
|
||||
if (hydrationCallbacks !== null) {
|
||||
const onHydrated = hydrationCallbacks.onHydrated;
|
||||
if (onHydrated) {
|
||||
onHydrated(suspenseInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(finishedWork, finishedWork.return, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user