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 12, 2020
1 parent b6e1d08 commit e51e75b
Show file tree
Hide file tree
Showing 13 changed files with 647 additions and 4 deletions.
8 changes: 4 additions & 4 deletions packages/react-reconciler/src/ReactFiberCommitWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,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 @@ -308,7 +308,7 @@ function commitBeforeMutationLifeCycles(
);
}

function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {
export function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
Expand All @@ -320,15 +320,15 @@ function commitHookEffectListUnmount(tag: number, finishedWork: Fiber) {
const destroy = effect.destroy;
effect.destroy = undefined;
if (destroy !== undefined) {
destroy();
safelyCallDestroy(finishedWork, destroy);
}
}
effect = effect.next;
} while (effect !== firstEffect);
}
}

function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
export function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
Expand Down
208 changes: 208 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
enableDebugTracing,
enableSchedulingProfiler,
enableScopeAPI,
enableDoubleInvokingEffects,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import invariant from 'shared/invariant';
Expand All @@ -55,6 +56,7 @@ import {
NoEffect as NoHookEffect,
HasEffect as HookHasEffect,
Passive as HookPassive,
Layout as HookLayout,
} from './ReactHookEffectTags';
import {
logCommitStarted,
Expand Down Expand Up @@ -208,9 +210,12 @@ import {
commitDeletion,
commitDetachRef,
commitAttachRef,
commitHookEffectListUnmount,
commitHookEffectListMount,
commitPassiveEffectDurations,
commitResetTextContent,
isSuspenseBoundaryBeingHidden,
safelyCallComponentWillUnmount,
safelyCallDestroy,
} from './ReactFiberCommitWork.new';
import {enqueueUpdate} from './ReactUpdateQueue.new';
Expand Down Expand Up @@ -2326,6 +2331,14 @@ function commitRootImpl(root, renderPriorityLevel) {
}
}

if (enableDoubleInvokingEffects) {
if (__DEV__) {
if (!rootDidHavePassiveEffects) {
doubleInvokeEffectsInDEV(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 @@ -3027,6 +3040,12 @@ function flushPassiveEffectsImpl() {
nestedPassiveUpdateCount =
rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;

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

return true;
}

Expand Down Expand Up @@ -3879,6 +3898,195 @@ function finishPendingInteractions(root, committedLanes) {
}
}

function doubleInvokeEffectsInDEV(fiber, hasPassiveEffects) {
if (__DEV__) {
invokeLayoutEffectsUnmountInDEV(fiber);
invokeLayoutEffectsMountInDEV(fiber);

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

function invokeLayoutEffectsUnmountInDEV(firstChild) {
// 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) {
// 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 (__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 (__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;
}
}
}

// `act` testing API
//
// TODO: This is mostly a copy-paste from the legacy `act`, which does not have
Expand Down
Loading

0 comments on commit e51e75b

Please sign in to comment.