Skip to content

Commit

Permalink
offscreen double invoke effects
Browse files Browse the repository at this point in the history
  • Loading branch information
lunaruan committed Aug 14, 2020
1 parent dab0854 commit b4f716a
Show file tree
Hide file tree
Showing 13 changed files with 745 additions and 1 deletion.
212 changes: 211 additions & 1 deletion packages/react-reconciler/src/ReactFiberCommitWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
enableFundamentalAPI,
enableSuspenseCallback,
enableScopeAPI,
enableDoubleInvokingEffects,
} from 'shared/ReactFeatureFlags';
import {
FunctionComponent,
Expand Down Expand Up @@ -71,6 +72,7 @@ import {
Placement,
Snapshot,
Update,
Passive,
} from './ReactSideEffectTags';
import getComponentName from 'shared/getComponentName';
import invariant from 'shared/invariant';
Expand Down Expand Up @@ -132,6 +134,7 @@ import {
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
import {
NoEffect as NoSubtreeTag,
Layout as LayoutSubtreeTag,
Passive as PassiveSubtreeTag,
} from './ReactSubtreeTags';

Expand Down Expand Up @@ -162,7 +165,7 @@ const callComponentWillUnmountWithTimer = function(current, instance) {
};

// Capture errors so they don't interrupt unmounting.
function safelyCallComponentWillUnmount(current, instance) {
export function safelyCallComponentWillUnmount(current: Fiber, instance: any) {
if (__DEV__) {
invokeGuardedCallback(
null,
Expand Down Expand Up @@ -1868,6 +1871,212 @@ function commitPassiveLifeCycles(finishedWork: Fiber): void {
}
}

function commitDoubleInvokeEffectsInDEV(
fiber: Fiber,
hasPassiveEffects: boolean,
) {
if (enableDoubleInvokingEffects) {
if (__DEV__) {
invokeLayoutEffectsUnmountInDEV(fiber);
if (hasPassiveEffects) {
invokePassiveEffectsUnmountInDEV(fiber);
}

invokeLayoutEffectsMountInDEV(fiber);
if (hasPassiveEffects) {
invokePassiveEffectsMountInDEV(fiber);
}
}
}
}

function invokeLayoutEffectsUnmountInDEV(firstChild) {
if (enableDoubleInvokingEffects) {
if (__DEV__) {
// unmount layout effects
let fiber = firstChild;
while (fiber !== null) {
if (fiber.child !== null) {
// Should we add a separate subtree tag for this?
const primarySubtreeTag = fiber.subtreeTag & LayoutSubtreeTag;
if (primarySubtreeTag !== NoSubtreeTag) {
invokeLayoutEffectsUnmountInDEV(fiber.child);
}
}

const effectTag = fiber.effectTag;
const current = fiber.alternate;
// This is a mount
if (current === null) {
if (effectTag & Update) {
switch (fiber.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
case Block: {
invokeGuardedCallback(
null,
commitHookEffectListUnmount,
null,
HookLayout | HookHasEffect,
fiber,
);
if (hasCaughtError()) {
const unmountError = clearCaughtError();
captureCommitPhaseError(fiber, unmountError);
}
break;
}
case ClassComponent: {
const instance = fiber.stateNode;
if (typeof instance.componentWillUnmount === 'function') {
safelyCallComponentWillUnmount(fiber, instance);
}
break;
}
}
}
}
fiber = fiber.sibling;
}
}
}
}

function invokeLayoutEffectsMountInDEV(firstChild) {
if (enableDoubleInvokingEffects) {
// mount layout effects
if (__DEV__) {
let fiber = firstChild;
while (fiber !== null) {
if (fiber.child !== null) {
// Should we add a separate subtree tag for this?
const primarySubtreeTag = fiber.subtreeTag & LayoutSubtreeTag;
if (primarySubtreeTag !== NoSubtreeTag) {
invokeLayoutEffectsMountInDEV(fiber.child);
}
}

const effectTag = fiber.effectTag;
const current = fiber.alternate;
if (current === null) {
if (effectTag & Update) {
switch (fiber.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
case Block: {
invokeGuardedCallback(
null,
commitHookEffectListMount,
null,
HookLayout | HookHasEffect,
fiber,
);
if (hasCaughtError()) {
const mountError = clearCaughtError();
captureCommitPhaseError(fiber, mountError);
}
break;
}
case ClassComponent: {
const instance = fiber.stateNode;
instance.componentDidMount();
break;
}
}
}
}
fiber = fiber.sibling;
}
}
}
}

function invokePassiveEffectsUnmountInDEV(firstChild): void {
if (enableDoubleInvokingEffects) {
if (__DEV__) {
let fiber = firstChild;
while (fiber !== null) {
if (fiber.child !== null) {
const primarySubtreeTag = fiber.subtreeTag & PassiveSubtreeTag;
if (primarySubtreeTag !== NoSubtreeTag) {
invokePassiveEffectsUnmountInDEV(fiber.child);
}
}

const current = fiber.alternate;
if (current === null) {
switch (fiber.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
case Block: {
if (fiber.effectTag & Passive) {
invokeGuardedCallback(
null,
commitHookEffectListUnmount,
null,
HookPassive | HookHasEffect,
fiber,
);
if (hasCaughtError()) {
const unmountError = clearCaughtError();
captureCommitPhaseError(fiber, unmountError);
}
}
break;
}
}
}
fiber = fiber.sibling;
}
}
}
}

function invokePassiveEffectsMountInDEV(firstChild): void {
if (enableDoubleInvokingEffects) {
if (__DEV__) {
let fiber = firstChild;
while (fiber !== null) {
if (fiber.child !== null) {
const primarySubtreeTag = fiber.subtreeTag & PassiveSubtreeTag;
if (primarySubtreeTag !== NoSubtreeTag) {
invokePassiveEffectsMountInDEV(fiber.child);
}
}

const current = fiber.alternate;
if (current === null) {
switch (fiber.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
case Block: {
if (fiber.effectTag & Passive) {
invokeGuardedCallback(
null,
commitHookEffectListMount,
null,
HookPassive | HookHasEffect,
fiber,
);
if (hasCaughtError()) {
const mountError = clearCaughtError();
captureCommitPhaseError(fiber, mountError);
}
}
break;
}
}
}
fiber = fiber.sibling;
}
}
}
}

export {
commitBeforeMutationLifeCycles,
commitResetTextContent,
Expand All @@ -1880,4 +2089,5 @@ export {
commitPassiveUnmount,
commitPassiveWork,
commitPassiveLifeCycles,
commitDoubleInvokeEffectsInDEV,
};
16 changes: 16 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
enableDebugTracing,
enableSchedulingProfiler,
enableScopeAPI,
enableDoubleInvokingEffects,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import invariant from 'shared/invariant';
Expand Down Expand Up @@ -211,6 +212,7 @@ import {
commitPassiveEffectDurations,
commitResetTextContent,
isSuspenseBoundaryBeingHidden,
commitDoubleInvokeEffectsInDEV,
} from './ReactFiberCommitWork.new';
import {enqueueUpdate} from './ReactUpdateQueue.new';
import {resetContextDependencies} from './ReactFiberNewContext.new';
Expand Down Expand Up @@ -2323,6 +2325,14 @@ function commitRootImpl(root, renderPriorityLevel) {
}
}

if (enableDoubleInvokingEffects) {
if (__DEV__) {
if (!rootDidHavePassiveEffects) {
commitDoubleInvokeEffectsInDEV(root.current, false);
}
}
}

if (remainingLanes === SyncLane) {
// Count the number of times the root synchronously re-renders without
// finishing. If there are too many, it indicates an infinite update loop.
Expand Down Expand Up @@ -2892,6 +2902,12 @@ function flushPassiveEffectsImpl() {
nestedPassiveUpdateCount =
rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;

if (enableDoubleInvokingEffects) {
if (__DEV__) {
commitDoubleInvokeEffectsInDEV(root.current, true);
}
}

return true;
}

Expand Down
Loading

0 comments on commit b4f716a

Please sign in to comment.