Skip to content

Commit 8cee981

Browse files
committed
offscreen double invoke effects
1 parent dab0854 commit 8cee981

13 files changed

+649
-1
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import {
7171
Placement,
7272
Snapshot,
7373
Update,
74+
Passive,
7475
} from './ReactSideEffectTags';
7576
import getComponentName from 'shared/getComponentName';
7677
import invariant from 'shared/invariant';
@@ -132,6 +133,7 @@ import {
132133
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
133134
import {
134135
NoEffect as NoSubtreeTag,
136+
Layout as LayoutSubtreeTag,
135137
Passive as PassiveSubtreeTag,
136138
} from './ReactSubtreeTags';
137139

@@ -162,7 +164,7 @@ const callComponentWillUnmountWithTimer = function(current, instance) {
162164
};
163165

164166
// Capture errors so they don't interrupt unmounting.
165-
function safelyCallComponentWillUnmount(current, instance) {
167+
export function safelyCallComponentWillUnmount(current: Fiber, instance: any) {
166168
if (__DEV__) {
167169
invokeGuardedCallback(
168170
null,
@@ -1868,6 +1870,200 @@ function commitPassiveLifeCycles(finishedWork: Fiber): void {
18681870
}
18691871
}
18701872

1873+
function commitDoubleInvokeEffectsInDEV(
1874+
fiber: Fiber,
1875+
hasPassiveEffects: boolean,
1876+
) {
1877+
if (__DEV__) {
1878+
invokeLayoutEffectsUnmountInDEV(fiber);
1879+
if (hasPassiveEffects) {
1880+
invokePassiveEffectsUnmountInDEV(fiber);
1881+
}
1882+
1883+
invokeLayoutEffectsMountInDEV(fiber);
1884+
if (hasPassiveEffects) {
1885+
invokePassiveEffectsMountInDEV(fiber);
1886+
}
1887+
}
1888+
}
1889+
1890+
function invokeLayoutEffectsUnmountInDEV(firstChild) {
1891+
// unmount layout effects
1892+
let fiber = firstChild;
1893+
while (fiber !== null) {
1894+
if (fiber.child !== null) {
1895+
// Should we add a separate subtree tag for this?
1896+
const primarySubtreeTag = fiber.subtreeTag & LayoutSubtreeTag;
1897+
if (primarySubtreeTag !== NoSubtreeTag) {
1898+
invokeLayoutEffectsUnmountInDEV(fiber.child);
1899+
}
1900+
}
1901+
1902+
const effectTag = fiber.effectTag;
1903+
const current = fiber.alternate;
1904+
// This is a mount
1905+
if (current === null) {
1906+
if (effectTag & Update) {
1907+
switch (fiber.tag) {
1908+
case FunctionComponent:
1909+
case ForwardRef:
1910+
case SimpleMemoComponent:
1911+
case Block: {
1912+
invokeGuardedCallback(
1913+
null,
1914+
commitHookEffectListUnmount,
1915+
null,
1916+
HookLayout | HookHasEffect,
1917+
fiber,
1918+
);
1919+
if (hasCaughtError()) {
1920+
const unmountError = clearCaughtError();
1921+
captureCommitPhaseError(fiber, unmountError);
1922+
}
1923+
break;
1924+
}
1925+
case ClassComponent: {
1926+
const instance = fiber.stateNode;
1927+
if (typeof instance.componentWillUnmount === 'function') {
1928+
safelyCallComponentWillUnmount(fiber, instance);
1929+
}
1930+
break;
1931+
}
1932+
}
1933+
}
1934+
}
1935+
fiber = fiber.sibling;
1936+
}
1937+
}
1938+
1939+
function invokeLayoutEffectsMountInDEV(firstChild) {
1940+
// mount layout effects
1941+
if (__DEV__) {
1942+
let fiber = firstChild;
1943+
while (fiber !== null) {
1944+
if (fiber.child !== null) {
1945+
// Should we add a separate subtree tag for this?
1946+
const primarySubtreeTag = fiber.subtreeTag & LayoutSubtreeTag;
1947+
if (primarySubtreeTag !== NoSubtreeTag) {
1948+
invokeLayoutEffectsMountInDEV(fiber.child);
1949+
}
1950+
}
1951+
1952+
const effectTag = fiber.effectTag;
1953+
const current = fiber.alternate;
1954+
if (current === null) {
1955+
if (effectTag & Update) {
1956+
switch (fiber.tag) {
1957+
case FunctionComponent:
1958+
case ForwardRef:
1959+
case SimpleMemoComponent:
1960+
case Block: {
1961+
invokeGuardedCallback(
1962+
null,
1963+
commitHookEffectListMount,
1964+
null,
1965+
HookLayout | HookHasEffect,
1966+
fiber,
1967+
);
1968+
if (hasCaughtError()) {
1969+
const mountError = clearCaughtError();
1970+
captureCommitPhaseError(fiber, mountError);
1971+
}
1972+
break;
1973+
}
1974+
case ClassComponent: {
1975+
const instance = fiber.stateNode;
1976+
instance.componentDidMount();
1977+
break;
1978+
}
1979+
}
1980+
}
1981+
}
1982+
fiber = fiber.sibling;
1983+
}
1984+
}
1985+
}
1986+
1987+
function invokePassiveEffectsUnmountInDEV(firstChild): void {
1988+
if (__DEV__) {
1989+
let fiber = firstChild;
1990+
while (fiber !== null) {
1991+
if (fiber.child !== null) {
1992+
const primarySubtreeTag = fiber.subtreeTag & PassiveSubtreeTag;
1993+
if (primarySubtreeTag !== NoSubtreeTag) {
1994+
invokePassiveEffectsUnmountInDEV(fiber.child);
1995+
}
1996+
}
1997+
1998+
const current = fiber.alternate;
1999+
if (current === null) {
2000+
switch (fiber.tag) {
2001+
case FunctionComponent:
2002+
case ForwardRef:
2003+
case SimpleMemoComponent:
2004+
case Block: {
2005+
if (fiber.effectTag & Passive) {
2006+
invokeGuardedCallback(
2007+
null,
2008+
commitHookEffectListUnmount,
2009+
null,
2010+
HookPassive | HookHasEffect,
2011+
fiber,
2012+
);
2013+
if (hasCaughtError()) {
2014+
const unmountError = clearCaughtError();
2015+
captureCommitPhaseError(fiber, unmountError);
2016+
}
2017+
}
2018+
break;
2019+
}
2020+
}
2021+
}
2022+
fiber = fiber.sibling;
2023+
}
2024+
}
2025+
}
2026+
2027+
function invokePassiveEffectsMountInDEV(firstChild): void {
2028+
if (__DEV__) {
2029+
let fiber = firstChild;
2030+
while (fiber !== null) {
2031+
if (fiber.child !== null) {
2032+
const primarySubtreeTag = fiber.subtreeTag & PassiveSubtreeTag;
2033+
if (primarySubtreeTag !== NoSubtreeTag) {
2034+
invokePassiveEffectsMountInDEV(fiber.child);
2035+
}
2036+
}
2037+
2038+
const current = fiber.alternate;
2039+
if (current === null) {
2040+
switch (fiber.tag) {
2041+
case FunctionComponent:
2042+
case ForwardRef:
2043+
case SimpleMemoComponent:
2044+
case Block: {
2045+
if (fiber.effectTag & Passive) {
2046+
invokeGuardedCallback(
2047+
null,
2048+
commitHookEffectListMount,
2049+
null,
2050+
HookPassive | HookHasEffect,
2051+
fiber,
2052+
);
2053+
if (hasCaughtError()) {
2054+
const mountError = clearCaughtError();
2055+
captureCommitPhaseError(fiber, mountError);
2056+
}
2057+
}
2058+
break;
2059+
}
2060+
}
2061+
}
2062+
fiber = fiber.sibling;
2063+
}
2064+
}
2065+
}
2066+
18712067
export {
18722068
commitBeforeMutationLifeCycles,
18732069
commitResetTextContent,
@@ -1880,4 +2076,5 @@ export {
18802076
commitPassiveUnmount,
18812077
commitPassiveWork,
18822078
commitPassiveLifeCycles,
2079+
commitDoubleInvokeEffectsInDEV,
18832080
};

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
enableDebugTracing,
3131
enableSchedulingProfiler,
3232
enableScopeAPI,
33+
enableDoubleInvokingEffects,
3334
} from 'shared/ReactFeatureFlags';
3435
import ReactSharedInternals from 'shared/ReactSharedInternals';
3536
import invariant from 'shared/invariant';
@@ -211,6 +212,7 @@ import {
211212
commitPassiveEffectDurations,
212213
commitResetTextContent,
213214
isSuspenseBoundaryBeingHidden,
215+
commitDoubleInvokeEffectsInDEV,
214216
} from './ReactFiberCommitWork.new';
215217
import {enqueueUpdate} from './ReactUpdateQueue.new';
216218
import {resetContextDependencies} from './ReactFiberNewContext.new';
@@ -2323,6 +2325,14 @@ function commitRootImpl(root, renderPriorityLevel) {
23232325
}
23242326
}
23252327

2328+
if (enableDoubleInvokingEffects) {
2329+
if (__DEV__) {
2330+
if (!rootDidHavePassiveEffects) {
2331+
commitDoubleInvokeEffectsInDEV(root.current, false);
2332+
}
2333+
}
2334+
}
2335+
23262336
if (remainingLanes === SyncLane) {
23272337
// Count the number of times the root synchronously re-renders without
23282338
// finishing. If there are too many, it indicates an infinite update loop.
@@ -2892,6 +2902,12 @@ function flushPassiveEffectsImpl() {
28922902
nestedPassiveUpdateCount =
28932903
rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
28942904

2905+
if (enableDoubleInvokingEffects) {
2906+
if (__DEV__) {
2907+
commitDoubleInvokeEffectsInDEV(root.current, true);
2908+
}
2909+
}
2910+
28952911
return true;
28962912
}
28972913

0 commit comments

Comments
 (0)