mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
@@ -17,7 +17,6 @@ beforeEach(() => {
|
||||
|
||||
// Don't feel too guilty if you have to delete this test.
|
||||
// @gate dfsEffectsRefactor
|
||||
// @gate new
|
||||
// @gate __DEV__
|
||||
test('warns in DEV if return pointer is inconsistent', async () => {
|
||||
const {useRef, useLayoutEffect} = React;
|
||||
|
||||
@@ -282,22 +282,13 @@ function ChildReconciler(shouldTrackSideEffects) {
|
||||
childToDelete.nextEffect = null;
|
||||
childToDelete.flags = (childToDelete.flags & StaticMask) | Deletion;
|
||||
|
||||
let deletions = returnFiber.deletions;
|
||||
const deletions = returnFiber.deletions;
|
||||
if (deletions === null) {
|
||||
deletions = returnFiber.deletions = [childToDelete];
|
||||
returnFiber.deletions = [childToDelete];
|
||||
returnFiber.flags |= ChildDeletion;
|
||||
} else {
|
||||
deletions.push(childToDelete);
|
||||
}
|
||||
// Stash a reference to the return fiber's deletion array on each of the
|
||||
// deleted children. This is really weird, but it's a temporary workaround
|
||||
// while we're still using the effect list to traverse effect fibers. A
|
||||
// better workaround would be to follow the `.return` pointer in the commit
|
||||
// phase, but unfortunately we can't assume that `.return` points to the
|
||||
// correct fiber, even in the commit phase, because `findDOMNode` might
|
||||
// mutate it.
|
||||
// TODO: Remove this line.
|
||||
childToDelete.deletions = deletions;
|
||||
}
|
||||
|
||||
function deleteRemainingChildren(
|
||||
|
||||
@@ -2203,14 +2203,13 @@ function updateSuspensePrimaryChildren(
|
||||
currentFallbackChildFragment.flags =
|
||||
(currentFallbackChildFragment.flags & StaticMask) | Deletion;
|
||||
workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChildFragment;
|
||||
let deletions = workInProgress.deletions;
|
||||
const deletions = workInProgress.deletions;
|
||||
if (deletions === null) {
|
||||
deletions = workInProgress.deletions = [currentFallbackChildFragment];
|
||||
workInProgress.deletions = [currentFallbackChildFragment];
|
||||
workInProgress.flags |= ChildDeletion;
|
||||
} else {
|
||||
deletions.push(currentFallbackChildFragment);
|
||||
}
|
||||
currentFallbackChildFragment.deletions = deletions;
|
||||
}
|
||||
|
||||
workInProgress.child = primaryChildFragment;
|
||||
@@ -3194,14 +3193,13 @@ function remountFiber(
|
||||
current.nextEffect = null;
|
||||
current.flags = (current.flags & StaticMask) | Deletion;
|
||||
|
||||
let deletions = returnFiber.deletions;
|
||||
const deletions = returnFiber.deletions;
|
||||
if (deletions === null) {
|
||||
deletions = returnFiber.deletions = [current];
|
||||
returnFiber.deletions = [current];
|
||||
returnFiber.flags |= ChildDeletion;
|
||||
} else {
|
||||
deletions.push(current);
|
||||
}
|
||||
current.deletions = deletions;
|
||||
|
||||
newWorkInProgress.flags |= Placement;
|
||||
|
||||
|
||||
@@ -66,11 +66,18 @@ import {
|
||||
NoFlags,
|
||||
ContentReset,
|
||||
Placement,
|
||||
PlacementAndUpdate,
|
||||
ChildDeletion,
|
||||
Snapshot,
|
||||
Update,
|
||||
Callback,
|
||||
Ref,
|
||||
Hydrating,
|
||||
HydratingAndUpdate,
|
||||
Passive,
|
||||
MutationMask,
|
||||
PassiveMask,
|
||||
LayoutMask,
|
||||
PassiveUnmountPendingDev,
|
||||
} from './ReactFiberFlags';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
@@ -490,326 +497,341 @@ export function commitPassiveEffectDurations(
|
||||
}
|
||||
}
|
||||
|
||||
function commitLifeCycles(
|
||||
function commitLayoutEffectOnFiber(
|
||||
finishedRoot: FiberRoot,
|
||||
current: Fiber | null,
|
||||
finishedWork: Fiber,
|
||||
committedLanes: Lanes,
|
||||
): void {
|
||||
switch (finishedWork.tag) {
|
||||
case FunctionComponent:
|
||||
case ForwardRef:
|
||||
case SimpleMemoComponent: {
|
||||
// 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);
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} else {
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
}
|
||||
|
||||
schedulePassiveEffects(finishedWork);
|
||||
return;
|
||||
}
|
||||
case ClassComponent: {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (finishedWork.flags & Update) {
|
||||
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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} else {
|
||||
instance.componentDidMount();
|
||||
if ((finishedWork.flags & (Update | Callback)) !== NoFlags) {
|
||||
switch (finishedWork.tag) {
|
||||
case FunctionComponent:
|
||||
case ForwardRef:
|
||||
case SimpleMemoComponent: {
|
||||
// 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);
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} 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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || 'instance',
|
||||
);
|
||||
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
|
||||
}
|
||||
|
||||
schedulePassiveEffects(finishedWork);
|
||||
break;
|
||||
}
|
||||
case ClassComponent: {
|
||||
const instance = finishedWork.stateNode;
|
||||
if (finishedWork.flags & Update) {
|
||||
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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidMount();
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} else {
|
||||
instance.componentDidMount();
|
||||
}
|
||||
} 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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || 'instance',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
enableProfilerTimer &&
|
||||
enableProfilerCommitHooks &&
|
||||
finishedWork.mode & ProfileMode
|
||||
) {
|
||||
try {
|
||||
startLayoutEffectTimer();
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} else {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
} finally {
|
||||
recordLayoutEffectDuration(finishedWork);
|
||||
}
|
||||
} else {
|
||||
instance.componentDidUpdate(
|
||||
prevProps,
|
||||
prevState,
|
||||
instance.__reactInternalSnapshotBeforeUpdate,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || '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.
|
||||
commitUpdateQueue(finishedWork, updateQueue, instance);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostRoot: {
|
||||
// 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) {
|
||||
let instance = null;
|
||||
if (finishedWork.child !== null) {
|
||||
switch (finishedWork.child.tag) {
|
||||
case HostComponent:
|
||||
instance = getPublicInstance(finishedWork.child.stateNode);
|
||||
break;
|
||||
case ClassComponent:
|
||||
instance = finishedWork.child.stateNode;
|
||||
break;
|
||||
|
||||
// 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) {
|
||||
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.',
|
||||
getComponentName(finishedWork.type) || '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.',
|
||||
getComponentName(finishedWork.type) || '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.
|
||||
commitUpdateQueue(finishedWork, updateQueue, instance);
|
||||
}
|
||||
commitUpdateQueue(finishedWork, updateQueue, instance);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
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;
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case HostText: {
|
||||
// We have no life-cycles associated with text.
|
||||
return;
|
||||
}
|
||||
case HostPortal: {
|
||||
// We have no life-cycles associated with portals.
|
||||
return;
|
||||
}
|
||||
case Profiler: {
|
||||
if (enableProfilerTimer) {
|
||||
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';
|
||||
case HostRoot: {
|
||||
// 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) {
|
||||
let instance = null;
|
||||
if (finishedWork.child !== null) {
|
||||
switch (finishedWork.child.tag) {
|
||||
case HostComponent:
|
||||
instance = getPublicInstance(finishedWork.child.stateNode);
|
||||
break;
|
||||
case ClassComponent:
|
||||
instance = finishedWork.child.stateNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
commitUpdateQueue(finishedWork, updateQueue, instance);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HostComponent: {
|
||||
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;
|
||||
commitMount(instance, type, props, finishedWork);
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
if (enableSchedulerTracing) {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
finishedRoot.memoizedInteractions,
|
||||
);
|
||||
} else {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HostText: {
|
||||
// We have no life-cycles associated with text.
|
||||
break;
|
||||
}
|
||||
case HostPortal: {
|
||||
// We have no life-cycles associated with portals.
|
||||
break;
|
||||
}
|
||||
case Profiler: {
|
||||
if (enableProfilerTimer) {
|
||||
const {onCommit, onRender} = finishedWork.memoizedProps;
|
||||
const {effectDuration} = finishedWork.stateNode;
|
||||
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
const commitTime = getCommitTime();
|
||||
|
||||
let phase = current === null ? 'mount' : 'update';
|
||||
if (enableProfilerNestedUpdatePhase) {
|
||||
if (isCurrentUpdateNested()) {
|
||||
phase = 'nested-update';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onRender === 'function') {
|
||||
if (enableSchedulerTracing) {
|
||||
onCommit(
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
commitTime,
|
||||
finishedRoot.memoizedInteractions,
|
||||
);
|
||||
} else {
|
||||
onCommit(
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
finishedWork.actualDuration,
|
||||
finishedWork.treeBaseDuration,
|
||||
finishedWork.actualStartTime,
|
||||
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);
|
||||
if (enableProfilerCommitHooks) {
|
||||
if (typeof onCommit === 'function') {
|
||||
if (enableSchedulerTracing) {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
finishedRoot.memoizedInteractions,
|
||||
);
|
||||
} else {
|
||||
onCommit(
|
||||
finishedWork.memoizedProps.id,
|
||||
phase,
|
||||
effectDuration,
|
||||
commitTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
while (parentFiber !== null) {
|
||||
if (parentFiber.tag === Profiler) {
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break;
|
||||
// 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;
|
||||
while (parentFiber !== null) {
|
||||
if (parentFiber.tag === Profiler) {
|
||||
const parentStateNode = parentFiber.stateNode;
|
||||
parentStateNode.effectDuration += effectDuration;
|
||||
break;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
parentFiber = parentFiber.return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case SuspenseComponent: {
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
break;
|
||||
}
|
||||
case SuspenseListComponent:
|
||||
case IncompleteClassComponent:
|
||||
case FundamentalComponent:
|
||||
case ScopeComponent:
|
||||
case OffscreenComponent:
|
||||
case LegacyHiddenComponent:
|
||||
break;
|
||||
default:
|
||||
invariant(
|
||||
false,
|
||||
'This unit of work tag should not have side-effects. This error is ' +
|
||||
'likely caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (enableScopeAPI) {
|
||||
// TODO: This is a temporary solution that allowed us to transition away
|
||||
// from React Flare on www.
|
||||
if (finishedWork.flags & Ref && finishedWork.tag !== ScopeComponent) {
|
||||
commitAttachRef(finishedWork);
|
||||
}
|
||||
} else {
|
||||
if (finishedWork.flags & Ref) {
|
||||
commitAttachRef(finishedWork);
|
||||
}
|
||||
case SuspenseComponent: {
|
||||
commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);
|
||||
return;
|
||||
}
|
||||
case SuspenseListComponent:
|
||||
case IncompleteClassComponent:
|
||||
case FundamentalComponent:
|
||||
case ScopeComponent:
|
||||
case OffscreenComponent:
|
||||
case LegacyHiddenComponent:
|
||||
return;
|
||||
}
|
||||
invariant(
|
||||
false,
|
||||
'This unit of work tag should not have side-effects. This error is ' +
|
||||
'likely caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
}
|
||||
|
||||
function hideOrUnhideAllChildren(finishedWork, isHidden) {
|
||||
@@ -1823,12 +1845,254 @@ function commitResetTextContent(current: Fiber) {
|
||||
resetTextContent(current.stateNode);
|
||||
}
|
||||
|
||||
export function commitMutationEffects(
|
||||
root: FiberRoot,
|
||||
renderPriorityLevel: ReactPriorityLevel,
|
||||
firstChild: Fiber,
|
||||
) {
|
||||
nextEffect = firstChild;
|
||||
commitMutationEffects_begin(root, renderPriorityLevel);
|
||||
}
|
||||
|
||||
function commitMutationEffects_begin(
|
||||
root: FiberRoot,
|
||||
renderPriorityLevel: ReactPriorityLevel,
|
||||
) {
|
||||
while (nextEffect !== null) {
|
||||
const fiber = nextEffect;
|
||||
|
||||
// TODO: Should wrap this in flags check, too, as optimization
|
||||
const deletions = fiber.deletions;
|
||||
if (deletions !== null) {
|
||||
for (let i = 0; i < deletions.length; i++) {
|
||||
const childToDelete = deletions[i];
|
||||
if (__DEV__) {
|
||||
invokeGuardedCallback(
|
||||
null,
|
||||
commitDeletion,
|
||||
null,
|
||||
root,
|
||||
childToDelete,
|
||||
renderPriorityLevel,
|
||||
);
|
||||
if (hasCaughtError()) {
|
||||
const error = clearCaughtError();
|
||||
captureCommitPhaseError(childToDelete, error);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
commitDeletion(root, childToDelete, renderPriorityLevel);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(childToDelete, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const child = fiber.child;
|
||||
if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {
|
||||
ensureCorrectReturnPointer(child, fiber);
|
||||
nextEffect = child;
|
||||
} else {
|
||||
commitMutationEffects_complete(root, renderPriorityLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitMutationEffects_complete(
|
||||
root: FiberRoot,
|
||||
renderPriorityLevel: ReactPriorityLevel,
|
||||
) {
|
||||
while (nextEffect !== null) {
|
||||
const fiber = nextEffect;
|
||||
if (__DEV__) {
|
||||
setCurrentDebugFiberInDEV(fiber);
|
||||
invokeGuardedCallback(
|
||||
null,
|
||||
commitMutationEffectsOnFiber,
|
||||
null,
|
||||
fiber,
|
||||
root,
|
||||
renderPriorityLevel,
|
||||
);
|
||||
if (hasCaughtError()) {
|
||||
const error = clearCaughtError();
|
||||
captureCommitPhaseError(fiber, error);
|
||||
}
|
||||
resetCurrentDebugFiberInDEV();
|
||||
} else {
|
||||
try {
|
||||
commitMutationEffectsOnFiber(fiber, root, renderPriorityLevel);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(fiber, error);
|
||||
}
|
||||
}
|
||||
|
||||
const sibling = fiber.sibling;
|
||||
if (sibling !== null) {
|
||||
ensureCorrectReturnPointer(sibling, fiber.return);
|
||||
nextEffect = sibling;
|
||||
return;
|
||||
}
|
||||
|
||||
nextEffect = fiber.return;
|
||||
}
|
||||
}
|
||||
|
||||
function commitMutationEffectsOnFiber(
|
||||
finishedWork: Fiber,
|
||||
root: FiberRoot,
|
||||
renderPriorityLevel: ReactPriorityLevel,
|
||||
) {
|
||||
const flags = finishedWork.flags;
|
||||
|
||||
if (flags & ContentReset) {
|
||||
commitResetTextContent(finishedWork);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
const current = finishedWork.alternate;
|
||||
if (current !== null) {
|
||||
commitDetachRef(current);
|
||||
}
|
||||
if (enableScopeAPI) {
|
||||
// TODO: This is a temporary solution that allowed us to transition away
|
||||
// from React Flare on www.
|
||||
if (finishedWork.tag === ScopeComponent) {
|
||||
commitAttachRef(finishedWork);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The following switch statement is only concerned about placement,
|
||||
// updates, and deletions. To avoid needing to add a case for every possible
|
||||
// bitmap value, we remove the secondary effects from the effect tag and
|
||||
// switch on that value.
|
||||
const primaryFlags = flags & (Placement | Update | Hydrating);
|
||||
outer: switch (primaryFlags) {
|
||||
case Placement: {
|
||||
commitPlacement(finishedWork);
|
||||
// Clear the "placement" from effect tag so that we know that this is
|
||||
// inserted, before any life-cycles like componentDidMount gets called.
|
||||
// TODO: findDOMNode doesn't rely on this any more but isMounted does
|
||||
// and isMounted is deprecated anyway so we should be able to kill this.
|
||||
finishedWork.flags &= ~Placement;
|
||||
break;
|
||||
}
|
||||
case PlacementAndUpdate: {
|
||||
// Placement
|
||||
commitPlacement(finishedWork);
|
||||
// Clear the "placement" from effect tag so that we know that this is
|
||||
// inserted, before any life-cycles like componentDidMount gets called.
|
||||
finishedWork.flags &= ~Placement;
|
||||
|
||||
// Update
|
||||
const current = finishedWork.alternate;
|
||||
commitWork(current, finishedWork);
|
||||
break;
|
||||
}
|
||||
case Hydrating: {
|
||||
finishedWork.flags &= ~Hydrating;
|
||||
break;
|
||||
}
|
||||
case HydratingAndUpdate: {
|
||||
finishedWork.flags &= ~Hydrating;
|
||||
|
||||
// Update
|
||||
const current = finishedWork.alternate;
|
||||
commitWork(current, finishedWork);
|
||||
break;
|
||||
}
|
||||
case Update: {
|
||||
const current = finishedWork.alternate;
|
||||
commitWork(current, finishedWork);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function commitLayoutEffects(
|
||||
finishedWork: Fiber,
|
||||
root: FiberRoot,
|
||||
committedLanes: Lanes,
|
||||
): void {
|
||||
nextEffect = finishedWork;
|
||||
commitLayoutEffects_begin(finishedWork, root, committedLanes);
|
||||
}
|
||||
|
||||
function commitLayoutEffects_begin(
|
||||
subtreeRoot: Fiber,
|
||||
root: FiberRoot,
|
||||
committedLanes: Lanes,
|
||||
) {
|
||||
while (nextEffect !== null) {
|
||||
const fiber = nextEffect;
|
||||
const firstChild = fiber.child;
|
||||
if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {
|
||||
ensureCorrectReturnPointer(firstChild, fiber);
|
||||
nextEffect = firstChild;
|
||||
} else {
|
||||
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function commitLayoutMountEffects_complete(
|
||||
subtreeRoot: Fiber,
|
||||
root: FiberRoot,
|
||||
committedLanes: Lanes,
|
||||
) {
|
||||
while (nextEffect !== null) {
|
||||
const fiber = nextEffect;
|
||||
if ((fiber.flags & LayoutMask) !== NoFlags) {
|
||||
const current = fiber.alternate;
|
||||
if (__DEV__) {
|
||||
setCurrentDebugFiberInDEV(fiber);
|
||||
invokeGuardedCallback(
|
||||
null,
|
||||
commitLayoutEffectOnFiber,
|
||||
null,
|
||||
root,
|
||||
current,
|
||||
fiber,
|
||||
committedLanes,
|
||||
);
|
||||
if (hasCaughtError()) {
|
||||
const error = clearCaughtError();
|
||||
captureCommitPhaseError(fiber, error);
|
||||
}
|
||||
resetCurrentDebugFiberInDEV();
|
||||
} else {
|
||||
try {
|
||||
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
|
||||
} catch (error) {
|
||||
captureCommitPhaseError(fiber, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fiber === subtreeRoot) {
|
||||
nextEffect = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const sibling = fiber.sibling;
|
||||
if (sibling !== null) {
|
||||
ensureCorrectReturnPointer(sibling, fiber.return);
|
||||
nextEffect = sibling;
|
||||
return;
|
||||
}
|
||||
|
||||
nextEffect = fiber.return;
|
||||
}
|
||||
}
|
||||
|
||||
export function commitPassiveMountEffects(
|
||||
root: FiberRoot,
|
||||
firstChild: Fiber,
|
||||
finishedWork: Fiber,
|
||||
): void {
|
||||
nextEffect = firstChild;
|
||||
commitPassiveMountEffects_begin(firstChild, root);
|
||||
nextEffect = finishedWork;
|
||||
commitPassiveMountEffects_begin(finishedWork, root);
|
||||
}
|
||||
|
||||
function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
|
||||
@@ -2094,7 +2358,6 @@ export {
|
||||
commitPlacement,
|
||||
commitDeletion,
|
||||
commitWork,
|
||||
commitLifeCycles,
|
||||
commitAttachRef,
|
||||
commitDetachRef,
|
||||
};
|
||||
|
||||
@@ -144,14 +144,13 @@ function deleteHydratableInstance(
|
||||
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
|
||||
}
|
||||
|
||||
let deletions = returnFiber.deletions;
|
||||
const deletions = returnFiber.deletions;
|
||||
if (deletions === null) {
|
||||
deletions = returnFiber.deletions = [childToDelete];
|
||||
returnFiber.deletions = [childToDelete];
|
||||
returnFiber.flags |= ChildDeletion;
|
||||
} else {
|
||||
deletions.push(childToDelete);
|
||||
}
|
||||
childToDelete.deletions = deletions;
|
||||
}
|
||||
|
||||
function insertNonHydratedInstance(returnFiber: Fiber, fiber: Fiber) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
decoupleUpdatePriorityFromScheduler,
|
||||
enableDebugTracing,
|
||||
enableSchedulingProfiler,
|
||||
enableScopeAPI,
|
||||
disableSchedulerTimeoutInWorkLoop,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
@@ -116,7 +115,6 @@ import {
|
||||
ForwardRef,
|
||||
MemoComponent,
|
||||
SimpleMemoComponent,
|
||||
ScopeComponent,
|
||||
Profiler,
|
||||
} from './ReactWorkTags';
|
||||
import {LegacyRoot} from './ReactRootTags';
|
||||
@@ -124,20 +122,14 @@ import {
|
||||
NoFlags,
|
||||
PerformedWork,
|
||||
Placement,
|
||||
Update,
|
||||
PlacementAndUpdate,
|
||||
Deletion,
|
||||
ChildDeletion,
|
||||
Ref,
|
||||
ContentReset,
|
||||
Snapshot,
|
||||
Callback,
|
||||
Passive,
|
||||
PassiveStatic,
|
||||
Incomplete,
|
||||
HostEffectMask,
|
||||
Hydrating,
|
||||
HydratingAndUpdate,
|
||||
StaticMask,
|
||||
} from './ReactFiberFlags';
|
||||
import {
|
||||
@@ -190,14 +182,9 @@ import {
|
||||
} from './ReactFiberThrow.old';
|
||||
import {
|
||||
commitBeforeMutationLifeCycles as commitBeforeMutationEffectOnFiber,
|
||||
commitLifeCycles as commitLayoutEffectOnFiber,
|
||||
commitPlacement,
|
||||
commitWork,
|
||||
commitDeletion,
|
||||
commitDetachRef,
|
||||
commitAttachRef,
|
||||
commitLayoutEffects,
|
||||
commitMutationEffects,
|
||||
commitPassiveEffectDurations,
|
||||
commitResetTextContent,
|
||||
isSuspenseBoundaryBeingHidden,
|
||||
commitPassiveMountEffects,
|
||||
commitPassiveUnmountEffects,
|
||||
@@ -2032,32 +2019,7 @@ function commitRootImpl(root, renderPriorityLevel) {
|
||||
}
|
||||
|
||||
// The next phase is the mutation phase, where we mutate the host tree.
|
||||
nextEffect = firstEffect;
|
||||
do {
|
||||
if (__DEV__) {
|
||||
invokeGuardedCallback(
|
||||
null,
|
||||
commitMutationEffects,
|
||||
null,
|
||||
root,
|
||||
renderPriorityLevel,
|
||||
);
|
||||
if (hasCaughtError()) {
|
||||
invariant(nextEffect !== null, 'Should be working on an effect.');
|
||||
const error = clearCaughtError();
|
||||
captureCommitPhaseError(nextEffect, error);
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
commitMutationEffects(root, renderPriorityLevel);
|
||||
} catch (error) {
|
||||
invariant(nextEffect !== null, 'Should be working on an effect.');
|
||||
captureCommitPhaseError(nextEffect, error);
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
}
|
||||
} while (nextEffect !== null);
|
||||
commitMutationEffects(root, renderPriorityLevel, finishedWork);
|
||||
|
||||
if (shouldFireAfterActiveInstanceBlur) {
|
||||
afterActiveInstanceBlur();
|
||||
@@ -2073,28 +2035,24 @@ function commitRootImpl(root, renderPriorityLevel) {
|
||||
// The next phase is the layout phase, where we call effects that read
|
||||
// the host tree after it's been mutated. The idiomatic use case for this is
|
||||
// layout, but class component lifecycles also fire here for legacy reasons.
|
||||
nextEffect = firstEffect;
|
||||
do {
|
||||
if (__DEV__) {
|
||||
invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);
|
||||
if (hasCaughtError()) {
|
||||
invariant(nextEffect !== null, 'Should be working on an effect.');
|
||||
const error = clearCaughtError();
|
||||
captureCommitPhaseError(nextEffect, error);
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
commitLayoutEffects(root, lanes);
|
||||
} catch (error) {
|
||||
invariant(nextEffect !== null, 'Should be working on an effect.');
|
||||
captureCommitPhaseError(nextEffect, error);
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (enableDebugTracing) {
|
||||
logLayoutEffectsStarted(lanes);
|
||||
}
|
||||
} while (nextEffect !== null);
|
||||
}
|
||||
if (enableSchedulingProfiler) {
|
||||
markLayoutEffectsStarted(lanes);
|
||||
}
|
||||
commitLayoutEffects(finishedWork, root, lanes);
|
||||
if (__DEV__) {
|
||||
if (enableDebugTracing) {
|
||||
logLayoutEffectsStopped();
|
||||
}
|
||||
}
|
||||
|
||||
nextEffect = null;
|
||||
if (enableSchedulingProfiler) {
|
||||
markLayoutEffectsStopped();
|
||||
}
|
||||
|
||||
if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {
|
||||
rootCommittingMutationOrLayoutEffects = null;
|
||||
@@ -2309,166 +2267,6 @@ function commitBeforeMutationEffects() {
|
||||
}
|
||||
}
|
||||
|
||||
function commitMutationEffects(
|
||||
root: FiberRoot,
|
||||
renderPriorityLevel: ReactPriorityLevel,
|
||||
) {
|
||||
// TODO: Should probably move the bulk of this function to commitWork.
|
||||
while (nextEffect !== null) {
|
||||
setCurrentDebugFiberInDEV(nextEffect);
|
||||
|
||||
const flags = nextEffect.flags;
|
||||
|
||||
if (flags & ContentReset) {
|
||||
commitResetTextContent(nextEffect);
|
||||
}
|
||||
|
||||
if (flags & Ref) {
|
||||
const current = nextEffect.alternate;
|
||||
if (current !== null) {
|
||||
commitDetachRef(current);
|
||||
}
|
||||
if (enableScopeAPI) {
|
||||
// TODO: This is a temporary solution that allowed us to transition away
|
||||
// from React Flare on www.
|
||||
if (nextEffect.tag === ScopeComponent) {
|
||||
commitAttachRef(nextEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The following switch statement is only concerned about placement,
|
||||
// updates, and deletions. To avoid needing to add a case for every possible
|
||||
// bitmap value, we remove the secondary effects from the effect tag and
|
||||
// switch on that value.
|
||||
const primaryFlags = flags & (Placement | Update | Deletion | Hydrating);
|
||||
outer: switch (primaryFlags) {
|
||||
case Placement: {
|
||||
commitPlacement(nextEffect);
|
||||
// Clear the "placement" from effect tag so that we know that this is
|
||||
// inserted, before any life-cycles like componentDidMount gets called.
|
||||
// TODO: findDOMNode doesn't rely on this any more but isMounted does
|
||||
// and isMounted is deprecated anyway so we should be able to kill this.
|
||||
nextEffect.flags &= ~Placement;
|
||||
break;
|
||||
}
|
||||
case PlacementAndUpdate: {
|
||||
// Placement
|
||||
commitPlacement(nextEffect);
|
||||
// Clear the "placement" from effect tag so that we know that this is
|
||||
// inserted, before any life-cycles like componentDidMount gets called.
|
||||
nextEffect.flags &= ~Placement;
|
||||
|
||||
// Update
|
||||
const current = nextEffect.alternate;
|
||||
commitWork(current, nextEffect);
|
||||
break;
|
||||
}
|
||||
case Hydrating: {
|
||||
nextEffect.flags &= ~Hydrating;
|
||||
break;
|
||||
}
|
||||
case HydratingAndUpdate: {
|
||||
nextEffect.flags &= ~Hydrating;
|
||||
|
||||
// Update
|
||||
const current = nextEffect.alternate;
|
||||
commitWork(current, nextEffect);
|
||||
break;
|
||||
}
|
||||
case Update: {
|
||||
const current = nextEffect.alternate;
|
||||
commitWork(current, nextEffect);
|
||||
break;
|
||||
}
|
||||
case Deletion: {
|
||||
// Reached a deletion effect. Instead of commit this effect like we
|
||||
// normally do, we're going to use the `deletions` array of the parent.
|
||||
// However, because the effect list is sorted in depth-first order, we
|
||||
// can't wait until we reach the parent node, because the child effects
|
||||
// will have run in the meantime.
|
||||
//
|
||||
// So instead, we use a trick where the first time we hit a deletion
|
||||
// effect, we commit all the deletion effects that belong to that parent.
|
||||
//
|
||||
// This is an incremental step away from using the effect list and
|
||||
// toward a DFS + subtreeFlags traversal.
|
||||
//
|
||||
// A reference to the deletion array of the parent is also stored on
|
||||
// each of the deletions. This is really weird. It would be better to
|
||||
// follow the `.return` pointer, but unfortunately we can't assume that
|
||||
// `.return` points to the correct fiber, even in the commit phase,
|
||||
// because `findDOMNode` might mutate it.
|
||||
const deletedChild = nextEffect;
|
||||
const deletions = deletedChild.deletions;
|
||||
if (deletions !== null) {
|
||||
for (let i = 0; i < deletions.length; i++) {
|
||||
const deletion = deletions[i];
|
||||
// Clear the deletion effect so that we don't delete this node more
|
||||
// than once.
|
||||
deletion.flags &= ~Deletion;
|
||||
deletion.deletions = null;
|
||||
commitDeletion(root, deletion, renderPriorityLevel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resetCurrentDebugFiberInDEV();
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
}
|
||||
|
||||
function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes) {
|
||||
if (__DEV__) {
|
||||
if (enableDebugTracing) {
|
||||
logLayoutEffectsStarted(committedLanes);
|
||||
}
|
||||
}
|
||||
|
||||
if (enableSchedulingProfiler) {
|
||||
markLayoutEffectsStarted(committedLanes);
|
||||
}
|
||||
|
||||
// TODO: Should probably move the bulk of this function to commitWork.
|
||||
while (nextEffect !== null) {
|
||||
setCurrentDebugFiberInDEV(nextEffect);
|
||||
|
||||
const flags = nextEffect.flags;
|
||||
|
||||
if (flags & (Update | Callback)) {
|
||||
const current = nextEffect.alternate;
|
||||
commitLayoutEffectOnFiber(root, current, nextEffect, committedLanes);
|
||||
}
|
||||
|
||||
if (enableScopeAPI) {
|
||||
// TODO: This is a temporary solution that allowed us to transition away
|
||||
// from React Flare on www.
|
||||
if (flags & Ref && nextEffect.tag !== ScopeComponent) {
|
||||
commitAttachRef(nextEffect);
|
||||
}
|
||||
} else {
|
||||
if (flags & Ref) {
|
||||
commitAttachRef(nextEffect);
|
||||
}
|
||||
}
|
||||
|
||||
resetCurrentDebugFiberInDEV();
|
||||
nextEffect = nextEffect.nextEffect;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
if (enableDebugTracing) {
|
||||
logLayoutEffectsStopped();
|
||||
}
|
||||
}
|
||||
|
||||
if (enableSchedulingProfiler) {
|
||||
markLayoutEffectsStopped();
|
||||
}
|
||||
}
|
||||
|
||||
export function flushPassiveEffects(): boolean {
|
||||
// Returns whether passive effects were flushed.
|
||||
if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
|
||||
|
||||
@@ -47,7 +47,7 @@ const environmentFlags = {
|
||||
|
||||
// Turn these flags back on (or delete) once the effect list is removed in
|
||||
// favor of a depth-first traversal using `subtreeTags`.
|
||||
dfsEffectsRefactor: __VARIANT__,
|
||||
dfsEffectsRefactor: true,
|
||||
enableUseJSStackToTrackPassiveDurations: false,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user