(Temporarily) revert unmounting error boundaries changes (#20147)

This reverts commits bcca5a6ca7 and ffb749c95e, although neither revert cleanly since methods have been moved between the work-loop and commit-work files. This commit is a mostly manual effort of undoing the changes.
This commit is contained in:
Brian Vaughn
2020-11-09 10:14:24 -05:00
committed by GitHub
parent fc06cf8d35
commit 7a73d6a0f9
17 changed files with 100 additions and 931 deletions
@@ -2473,175 +2473,4 @@ describe('ReactErrorBoundaries', () => {
'Caught an error: gotta catch em all.',
);
});
// @gate skipUnmountedBoundaries
it('catches errors thrown in componentWillUnmount', () => {
class LocalErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Scheduler.unstable_yieldValue(
`ErrorBoundary static getDerivedStateFromError`,
);
return {error};
}
render() {
const {children, id, fallbackID} = this.props;
const {error} = this.state;
if (error) {
Scheduler.unstable_yieldValue(`${id} render error`);
return <Component id={fallbackID} />;
}
Scheduler.unstable_yieldValue(`${id} render success`);
return children || null;
}
}
class Component extends React.Component {
render() {
const {id} = this.props;
Scheduler.unstable_yieldValue('Component render ' + id);
return id;
}
}
class LocalBrokenComponentWillUnmount extends React.Component {
componentWillUnmount() {
Scheduler.unstable_yieldValue(
'BrokenComponentWillUnmount componentWillUnmount',
);
throw Error('Expected');
}
render() {
Scheduler.unstable_yieldValue('BrokenComponentWillUnmount render');
return 'broken';
}
}
const container = document.createElement('div');
ReactDOM.render(
<LocalErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
<LocalErrorBoundary id="InnerBoundary" fallbackID="InnerFallback">
<LocalBrokenComponentWillUnmount />
</LocalErrorBoundary>
</LocalErrorBoundary>,
container,
);
expect(container.firstChild.textContent).toBe('sibling');
expect(container.lastChild.textContent).toBe('broken');
expect(Scheduler).toHaveYielded([
'OuterBoundary render success',
'Component render sibling',
'InnerBoundary render success',
'BrokenComponentWillUnmount render',
]);
ReactDOM.render(
<LocalErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
</LocalErrorBoundary>,
container,
);
// React should skip over the unmounting boundary and find the nearest still-mounted boundary.
expect(container.firstChild.textContent).toBe('OuterFallback');
expect(container.lastChild.textContent).toBe('OuterFallback');
expect(Scheduler).toHaveYielded([
'OuterBoundary render success',
'Component render sibling',
'BrokenComponentWillUnmount componentWillUnmount',
'ErrorBoundary static getDerivedStateFromError',
'OuterBoundary render error',
'Component render OuterFallback',
]);
});
// @gate skipUnmountedBoundaries
it('catches errors thrown while detaching refs', () => {
class LocalErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Scheduler.unstable_yieldValue(
`ErrorBoundary static getDerivedStateFromError`,
);
return {error};
}
render() {
const {children, id, fallbackID} = this.props;
const {error} = this.state;
if (error) {
Scheduler.unstable_yieldValue(`${id} render error`);
return <Component id={fallbackID} />;
}
Scheduler.unstable_yieldValue(`${id} render success`);
return children || null;
}
}
class Component extends React.Component {
render() {
const {id} = this.props;
Scheduler.unstable_yieldValue('Component render ' + id);
return id;
}
}
class LocalBrokenCallbackRef extends React.Component {
_ref = ref => {
Scheduler.unstable_yieldValue('LocalBrokenCallbackRef ref ' + !!ref);
if (ref === null) {
throw Error('Expected');
}
};
render() {
Scheduler.unstable_yieldValue('LocalBrokenCallbackRef render');
return <div ref={this._ref}>ref</div>;
}
}
const container = document.createElement('div');
ReactDOM.render(
<LocalErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
<LocalErrorBoundary id="InnerBoundary" fallbackID="InnerFallback">
<LocalBrokenCallbackRef />
</LocalErrorBoundary>
</LocalErrorBoundary>,
container,
);
expect(container.firstChild.textContent).toBe('sibling');
expect(container.lastChild.textContent).toBe('ref');
expect(Scheduler).toHaveYielded([
'OuterBoundary render success',
'Component render sibling',
'InnerBoundary render success',
'LocalBrokenCallbackRef render',
'LocalBrokenCallbackRef ref true',
]);
ReactDOM.render(
<LocalErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
</LocalErrorBoundary>,
container,
);
// React should skip over the unmounting boundary and find the nearest still-mounted boundary.
expect(container.firstChild.textContent).toBe('OuterFallback');
expect(container.lastChild.textContent).toBe('OuterFallback');
expect(Scheduler).toHaveYielded([
'OuterBoundary render success',
'Component render sibling',
'LocalBrokenCallbackRef ref false',
'ErrorBoundary static getDerivedStateFromError',
'OuterBoundary render error',
'Component render OuterFallback',
]);
});
});
@@ -1669,28 +1669,16 @@ describe('DOMPluginEventSystem', () => {
function Test() {
React.useEffect(() => {
const clearClick1 = setClick1(
buttonRef.current,
targetListener1,
);
const clearClick2 = setClick2(
buttonRef.current,
targetListener2,
);
const clearClick3 = setClick3(
buttonRef.current,
targetListener3,
);
const clearClick4 = setClick4(
buttonRef.current,
targetListener4,
);
setClick1(buttonRef.current, targetListener1);
setClick2(buttonRef.current, targetListener2);
setClick3(buttonRef.current, targetListener3);
setClick4(buttonRef.current, targetListener4);
return () => {
clearClick1();
clearClick2();
clearClick3();
clearClick4();
setClick1();
setClick2();
setClick3();
setClick4();
};
});
@@ -1715,28 +1703,16 @@ describe('DOMPluginEventSystem', () => {
function Test2() {
React.useEffect(() => {
const clearClick1 = setClick1(
buttonRef.current,
targetListener1,
);
const clearClick2 = setClick2(
buttonRef.current,
targetListener2,
);
const clearClick3 = setClick3(
buttonRef.current,
targetListener3,
);
const clearClick4 = setClick4(
buttonRef.current,
targetListener4,
);
setClick1(buttonRef.current, targetListener1);
setClick2(buttonRef.current, targetListener2);
setClick3(buttonRef.current, targetListener3);
setClick4(buttonRef.current, targetListener4);
return () => {
clearClick1();
clearClick2();
clearClick3();
clearClick4();
setClick1();
setClick2();
setClick3();
setClick4();
};
});
@@ -185,11 +185,7 @@ const callComponentWillUnmountWithTimer = function(current, instance) {
};
// Capture errors so they don't interrupt unmounting.
function safelyCallComponentWillUnmount(
current: Fiber,
instance: any,
nearestMountedAncestor: Fiber | null,
) {
function safelyCallComponentWillUnmount(current, instance) {
if (__DEV__) {
invokeGuardedCallback(
null,
@@ -200,19 +196,19 @@ function safelyCallComponentWillUnmount(
);
if (hasCaughtError()) {
const unmountError = clearCaughtError();
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
captureCommitPhaseError(current, unmountError);
}
} else {
try {
callComponentWillUnmountWithTimer(current, instance);
} catch (unmountError) {
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
captureCommitPhaseError(current, unmountError);
}
}
}
/** @noinline */
function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
function safelyDetachRef(current: Fiber) {
const ref = current.ref;
if (ref !== null) {
if (typeof ref === 'function') {
@@ -231,7 +227,7 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
if (hasCaughtError()) {
const refError = clearCaughtError();
captureCommitPhaseError(current, nearestMountedAncestor, refError);
captureCommitPhaseError(current, refError);
}
} else {
try {
@@ -250,7 +246,7 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
ref(null);
}
} catch (refError) {
captureCommitPhaseError(current, nearestMountedAncestor, refError);
captureCommitPhaseError(current, refError);
}
}
} else {
@@ -259,32 +255,24 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
}
}
export function safelyCallDestroy(
current: Fiber,
nearestMountedAncestor: Fiber | null,
destroy: () => void,
) {
export function safelyCallDestroy(current: Fiber, destroy: () => void) {
if (__DEV__) {
invokeGuardedCallback(null, destroy, null);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(current, nearestMountedAncestor, error);
captureCommitPhaseError(current, error);
}
} else {
try {
destroy();
} catch (error) {
captureCommitPhaseError(current, nearestMountedAncestor, error);
captureCommitPhaseError(current, error);
}
}
}
/** @noinline */
function commitHookEffectListUnmount(
flags: HookFlags,
finishedWork: Fiber,
nearestMountedAncestor: Fiber | null,
) {
function commitHookEffectListUnmount(flags: HookFlags, finishedWork: Fiber) {
const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
@@ -296,7 +284,7 @@ function commitHookEffectListUnmount(
const destroy = effect.destroy;
effect.destroy = undefined;
if (destroy !== undefined) {
safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);
safelyCallDestroy(finishedWork, destroy);
}
}
effect = effect.next;
@@ -442,14 +430,14 @@ function recursivelyCommitBeforeMutationEffects(firstChild: Fiber) {
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitBeforeMutationEffectsOnFiber(fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
fiber = fiber.sibling;
@@ -492,14 +480,14 @@ function iterativelyCommitBeforeMutationEffects_complete() {
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitBeforeMutationEffectsOnFiber(fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
@@ -668,12 +656,7 @@ function recursivelyCommitMutationEffects(
while (fiber !== null) {
const deletions = fiber.deletions;
if (deletions !== null) {
commitMutationEffectsDeletions(
deletions,
fiber,
root,
renderPriorityLevel,
);
commitMutationEffectsDeletions(deletions, root, renderPriorityLevel);
}
if (fiber.child !== null) {
@@ -699,14 +682,14 @@ function recursivelyCommitMutationEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitMutationEffectsOnFiber(fiber, root, renderPriorityLevel);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
fiber = fiber.sibling;
@@ -723,12 +706,7 @@ function iterativelyCommitMutationEffects_begin(
// TODO: Should wrap this in flags check, too, as optimization
const deletions = fiber.deletions;
if (deletions !== null) {
commitMutationEffectsDeletions(
deletions,
fiber,
root,
renderPriorityLevel,
);
commitMutationEffectsDeletions(deletions, root, renderPriorityLevel);
}
const child = fiber.child;
@@ -759,14 +737,14 @@ function iterativelyCommitMutationEffects_complete(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitMutationEffectsOnFiber(fiber, root, renderPriorityLevel);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
@@ -855,7 +833,6 @@ function commitMutationEffectsOnFiber(
/** @noinline */
function commitMutationEffectsDeletions(
deletions: Array<Fiber>,
nearestMountedAncestor: Fiber,
root: FiberRoot,
renderPriorityLevel,
) {
@@ -868,23 +845,17 @@ function commitMutationEffectsDeletions(
null,
root,
childToDelete,
nearestMountedAncestor,
renderPriorityLevel,
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);
captureCommitPhaseError(childToDelete, error);
}
} else {
try {
commitDeletion(
root,
childToDelete,
nearestMountedAncestor,
renderPriorityLevel,
);
commitDeletion(root, childToDelete, renderPriorityLevel);
} catch (error) {
captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);
captureCommitPhaseError(childToDelete, error);
}
}
}
@@ -906,14 +877,14 @@ export function commitLayoutEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(finishedWork, null, error);
captureCommitPhaseError(finishedWork, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
recursivelyCommitLayoutEffects(finishedWork, finishedRoot);
} catch (error) {
captureCommitPhaseError(finishedWork, null, error);
captureCommitPhaseError(finishedWork, error);
}
}
} else {
@@ -951,7 +922,7 @@ function recursivelyCommitLayoutEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(child, finishedWork, error);
captureCommitPhaseError(child, error);
}
if (prevCurrentFiberInDEV !== null) {
setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);
@@ -962,7 +933,7 @@ function recursivelyCommitLayoutEffects(
try {
recursivelyCommitLayoutEffects(child, finishedRoot);
} catch (error) {
captureCommitPhaseError(child, finishedWork, error);
captureCommitPhaseError(child, error);
}
}
}
@@ -984,7 +955,7 @@ function recursivelyCommitLayoutEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(finishedWork, finishedWork.return, error);
captureCommitPhaseError(finishedWork, error);
}
if (prevCurrentFiberInDEV !== null) {
setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);
@@ -995,7 +966,7 @@ function recursivelyCommitLayoutEffects(
try {
commitLayoutEffectsForProfiler(finishedWork, finishedRoot);
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
captureCommitPhaseError(finishedWork, error);
}
}
}
@@ -1036,7 +1007,7 @@ function recursivelyCommitLayoutEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(child, finishedWork, error);
captureCommitPhaseError(child, error);
}
if (prevCurrentFiberInDEV !== null) {
setCurrentDebugFiberInDEV(prevCurrentFiberInDEV);
@@ -1047,7 +1018,7 @@ function recursivelyCommitLayoutEffects(
try {
recursivelyCommitLayoutEffects(child, finishedRoot);
} catch (error) {
captureCommitPhaseError(child, finishedWork, error);
captureCommitPhaseError(child, error);
}
}
}
@@ -1175,14 +1146,14 @@ function iterativelyCommitLayoutEffects_begin(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(finishedWork, finishedWork.return, error);
captureCommitPhaseError(finishedWork, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitLayoutEffectsForProfiler(finishedWork, finishedRoot);
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
captureCommitPhaseError(finishedWork, error);
}
}
}
@@ -1236,14 +1207,14 @@ function iterativelyCommitLayoutEffects_complete(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitLayoutEffectsOnFiber(finishedRoot, fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
}
@@ -1690,14 +1661,14 @@ function recursivelyCommitPassiveMountEffects(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitPassiveMountOnFiber(root, fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
}
@@ -1755,14 +1726,14 @@ function iterativelyCommitPassiveMountEffects_begin(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitProfilerPassiveEffect(root, fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
}
@@ -1816,14 +1787,14 @@ function iterativelyCommitPassiveMountEffects_complete(
);
if (hasCaughtError()) {
const error = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
resetCurrentDebugFiberInDEV();
} else {
try {
commitPassiveMountOnFiber(root, fiber);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
captureCommitPhaseError(fiber, error);
}
}
}
@@ -1862,7 +1833,6 @@ function recursivelyCommitPassiveUnmountEffects(firstChild: Fiber): void {
const fiberToDelete = deletions[i];
recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(
fiberToDelete,
fiber,
);
// Now that passive effects have been processed, it's safe to detach lingering pointers.
@@ -1906,7 +1876,6 @@ function iterativelyCommitPassiveUnmountEffects_begin() {
nextEffect = fiberToDelete;
iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(
fiberToDelete,
fiber,
);
// Now that passive effects have been processed, it's safe to detach lingering pointers.
@@ -1946,7 +1915,6 @@ function iterativelyCommitPassiveUnmountEffects_complete() {
function recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(
fiberToDelete: Fiber,
nearestMountedAncestor: Fiber,
): void {
if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {
// If any children have passive effects then traverse the subtree.
@@ -1955,27 +1923,20 @@ function recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(
// since that would not cover passive effects in siblings.
let child = fiberToDelete.child;
while (child !== null) {
recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(
child,
nearestMountedAncestor,
);
recursivelyCommitPassiveUnmountEffectsInsideOfDeletedTree(child);
child = child.sibling;
}
}
if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {
setCurrentDebugFiberInDEV(fiberToDelete);
commitPassiveUnmountInsideDeletedTreeOnFiber(
fiberToDelete,
nearestMountedAncestor,
);
commitPassiveUnmountInsideDeletedTreeOnFiber(fiberToDelete);
resetCurrentDebugFiberInDEV();
}
}
function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(
deletedSubtreeRoot: Fiber,
nearestMountedAncestor: Fiber,
) {
while (nextEffect !== null) {
const fiber = nextEffect;
@@ -1986,7 +1947,6 @@ function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(
} else {
iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_complete(
deletedSubtreeRoot,
nearestMountedAncestor,
);
}
}
@@ -1994,16 +1954,12 @@ function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_begin(
function iterativelyCommitPassiveUnmountEffectsInsideOfDeletedTree_complete(
deletedSubtreeRoot: Fiber,
nearestMountedAncestor: Fiber,
) {
while (nextEffect !== null) {
const fiber = nextEffect;
if ((fiber.flags & PassiveStatic) !== NoFlags) {
setCurrentDebugFiberInDEV(fiber);
commitPassiveUnmountInsideDeletedTreeOnFiber(
fiber,
nearestMountedAncestor,
);
commitPassiveUnmountInsideDeletedTreeOnFiber(fiber);
resetCurrentDebugFiberInDEV();
}
@@ -2118,7 +2074,6 @@ function commitDetachRef(current: Fiber) {
function commitUnmount(
finishedRoot: FiberRoot,
current: Fiber,
nearestMountedAncestor: Fiber,
renderPriorityLevel: ReactPriorityLevel,
): void {
onCommitUnmount(current);
@@ -2145,10 +2100,10 @@ function commitUnmount(
current.mode & ProfileMode
) {
startLayoutEffectTimer();
safelyCallDestroy(current, nearestMountedAncestor, destroy);
safelyCallDestroy(current, destroy);
recordLayoutEffectDuration(current);
} else {
safelyCallDestroy(current, nearestMountedAncestor, destroy);
safelyCallDestroy(current, destroy);
}
}
}
@@ -2159,19 +2114,15 @@ function commitUnmount(
return;
}
case ClassComponent: {
safelyDetachRef(current, nearestMountedAncestor);
safelyDetachRef(current);
const instance = current.stateNode;
if (typeof instance.componentWillUnmount === 'function') {
safelyCallComponentWillUnmount(
current,
instance,
nearestMountedAncestor,
);
safelyCallComponentWillUnmount(current, instance);
}
return;
}
case HostComponent: {
safelyDetachRef(current, nearestMountedAncestor);
safelyDetachRef(current);
return;
}
case HostPortal: {
@@ -2179,12 +2130,7 @@ function commitUnmount(
// We are also not using this parent because
// the portal will get pushed immediately.
if (supportsMutation) {
unmountHostComponents(
finishedRoot,
current,
nearestMountedAncestor,
renderPriorityLevel,
);
unmountHostComponents(finishedRoot, current, renderPriorityLevel);
} else if (supportsPersistence) {
emptyPortalContainer(current);
}
@@ -2214,7 +2160,7 @@ function commitUnmount(
}
case ScopeComponent: {
if (enableScopeAPI) {
safelyDetachRef(current, nearestMountedAncestor);
safelyDetachRef(current);
}
return;
}
@@ -2224,7 +2170,6 @@ function commitUnmount(
function commitNestedUnmounts(
finishedRoot: FiberRoot,
root: Fiber,
nearestMountedAncestor: Fiber,
renderPriorityLevel: ReactPriorityLevel,
): void {
// While we're inside a removed host node we don't want to call
@@ -2234,12 +2179,7 @@ function commitNestedUnmounts(
// we do an inner loop while we're still inside the host node.
let node: Fiber = root;
while (true) {
commitUnmount(
finishedRoot,
node,
nearestMountedAncestor,
renderPriorityLevel,
);
commitUnmount(finishedRoot, node, renderPriorityLevel);
// Visit children because they may contain more composite or host nodes.
// Skip portals because commitUnmount() currently visits them recursively.
if (
@@ -2520,10 +2460,9 @@ function insertOrAppendPlacementNode(
}
function unmountHostComponents(
finishedRoot: FiberRoot,
current: Fiber,
nearestMountedAncestor: Fiber,
renderPriorityLevel: ReactPriorityLevel,
finishedRoot,
current,
renderPriorityLevel,
): void {
// We only have the top Fiber that was deleted but we need to recurse down its
// children to find all the terminal nodes.
@@ -2572,12 +2511,7 @@ function unmountHostComponents(
}
if (node.tag === HostComponent || node.tag === HostText) {
commitNestedUnmounts(
finishedRoot,
node,
nearestMountedAncestor,
renderPriorityLevel,
);
commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);
// After all the children have unmounted, it is now safe to remove the
// node from the tree.
if (currentParentIsContainer) {
@@ -2594,12 +2528,7 @@ function unmountHostComponents(
// Don't visit children because we already visited them.
} else if (enableFundamentalAPI && node.tag === FundamentalComponent) {
const fundamentalNode = node.stateNode.instance;
commitNestedUnmounts(
finishedRoot,
node,
nearestMountedAncestor,
renderPriorityLevel,
);
commitNestedUnmounts(finishedRoot, node, renderPriorityLevel);
// After all the children have unmounted, it is now safe to remove the
// node from the tree.
if (currentParentIsContainer) {
@@ -2651,12 +2580,7 @@ function unmountHostComponents(
continue;
}
} else {
commitUnmount(
finishedRoot,
node,
nearestMountedAncestor,
renderPriorityLevel,
);
commitUnmount(finishedRoot, node, renderPriorityLevel);
// Visit children because we may find more host components below.
if (node.child !== null) {
node.child.return = node;
@@ -2686,26 +2610,15 @@ function unmountHostComponents(
function commitDeletion(
finishedRoot: FiberRoot,
current: Fiber,
nearestMountedAncestor: Fiber,
renderPriorityLevel: ReactPriorityLevel,
): void {
if (supportsMutation) {
// Recursively delete all host nodes from the parent.
// Detach refs and call componentWillUnmount() on the whole subtree.
unmountHostComponents(
finishedRoot,
current,
nearestMountedAncestor,
renderPriorityLevel,
);
unmountHostComponents(finishedRoot, current, renderPriorityLevel);
} else {
// Detach refs and call componentWillUnmount() on the whole subtree.
commitNestedUnmounts(
finishedRoot,
current,
nearestMountedAncestor,
renderPriorityLevel,
);
commitNestedUnmounts(finishedRoot, current, renderPriorityLevel);
}
const alternate = current.alternate;
detachFiberMutation(current);
@@ -2736,17 +2649,12 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
commitHookEffectListUnmount(
HookLayout | HookHasEffect,
finishedWork,
finishedWork.return,
);
} finally {
recordLayoutEffectDuration(finishedWork);
}
} else {
commitHookEffectListUnmount(
HookLayout | HookHasEffect,
finishedWork,
finishedWork.return,
);
commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);
}
return;
}
@@ -2800,20 +2708,12 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
) {
try {
startLayoutEffectTimer();
commitHookEffectListUnmount(
HookLayout | HookHasEffect,
finishedWork,
finishedWork.return,
);
commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);
} finally {
recordLayoutEffectDuration(finishedWork);
}
} else {
commitHookEffectListUnmount(
HookLayout | HookHasEffect,
finishedWork,
finishedWork.return,
);
commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);
}
return;
}
@@ -3049,28 +2949,17 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
finishedWork.mode & ProfileMode
) {
startPassiveEffectTimer();
commitHookEffectListUnmount(
HookPassive | HookHasEffect,
finishedWork,
finishedWork.return,
);
commitHookEffectListUnmount(HookPassive | HookHasEffect, finishedWork);
recordPassiveEffectDuration(finishedWork);
} else {
commitHookEffectListUnmount(
HookPassive | HookHasEffect,
finishedWork,
finishedWork.return,
);
commitHookEffectListUnmount(HookPassive | HookHasEffect, finishedWork);
}
break;
}
}
}
function commitPassiveUnmountInsideDeletedTreeOnFiber(
current: Fiber,
nearestMountedAncestor: Fiber | null,
): void {
function commitPassiveUnmountInsideDeletedTreeOnFiber(current: Fiber): void {
switch (current.tag) {
case FunctionComponent:
case ForwardRef:
@@ -3081,18 +2970,10 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
current.mode & ProfileMode
) {
startPassiveEffectTimer();
commitHookEffectListUnmount(
HookPassive,
current,
nearestMountedAncestor,
);
commitHookEffectListUnmount(HookPassive, current);
recordPassiveEffectDuration(current);
} else {
commitHookEffectListUnmount(
HookPassive,
current,
nearestMountedAncestor,
);
commitHookEffectListUnmount(HookPassive, current);
}
break;
}
@@ -3147,7 +3028,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
);
if (hasCaughtError()) {
const mountError = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, mountError);
captureCommitPhaseError(fiber, mountError);
}
break;
}
@@ -3156,7 +3037,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
invokeGuardedCallback(null, instance.componentDidMount, instance);
if (hasCaughtError()) {
const mountError = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, mountError);
captureCommitPhaseError(fiber, mountError);
}
break;
}
@@ -3181,7 +3062,7 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
);
if (hasCaughtError()) {
const mountError = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, mountError);
captureCommitPhaseError(fiber, mountError);
}
break;
}
@@ -3203,18 +3084,17 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
null,
HookLayout | HookHasEffect,
fiber,
fiber.return,
);
if (hasCaughtError()) {
const unmountError = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, unmountError);
captureCommitPhaseError(fiber, unmountError);
}
break;
}
case ClassComponent: {
const instance = fiber.stateNode;
if (typeof instance.componentWillUnmount === 'function') {
safelyCallComponentWillUnmount(fiber, instance, fiber.return);
safelyCallComponentWillUnmount(fiber, instance);
}
break;
}
@@ -3236,11 +3116,10 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
null,
HookPassive | HookHasEffect,
fiber,
fiber.return,
);
if (hasCaughtError()) {
const unmountError = clearCaughtError();
captureCommitPhaseError(fiber, fiber.return, unmountError);
captureCommitPhaseError(fiber, unmountError);
}
break;
}
@@ -27,7 +27,6 @@ import {
decoupleUpdatePriorityFromScheduler,
enableDebugTracing,
enableSchedulingProfiler,
skipUnmountedBoundaries,
enableDoubleInvokingEffects,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
@@ -2201,11 +2200,7 @@ function captureCommitPhaseErrorOnRoot(
}
}
export function captureCommitPhaseError(
sourceFiber: Fiber,
nearestMountedAncestor: Fiber | null,
error: mixed,
) {
export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {
if (sourceFiber.tag === HostRoot) {
// Error was thrown at the root. There is no parent, so the root
// itself should capture it.
@@ -2213,13 +2208,7 @@ export function captureCommitPhaseError(
return;
}
let fiber = null;
if (skipUnmountedBoundaries) {
fiber = nearestMountedAncestor;
} else {
fiber = sourceFiber.return;
}
let fiber = sourceFiber.return;
while (fiber !== null) {
if (fiber.tag === HostRoot) {
captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);
@@ -2298,10 +2298,7 @@ function commitBeforeMutationEffects() {
}
}
function commitMutationEffects(
root: FiberRoot,
renderPriorityLevel: ReactPriorityLevel,
) {
function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {
// TODO: Should probably move the bulk of this function to commitWork.
while (nextEffect !== null) {
setCurrentDebugFiberInDEV(nextEffect);
@@ -2760,7 +2757,6 @@ export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {
}
let fiber = sourceFiber.return;
while (fiber !== null) {
if (fiber.tag === HostRoot) {
captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);
@@ -2786,24 +2782,6 @@ export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {
markRootUpdated(root, SyncLane, eventTime);
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, SyncLane);
} else {
// This component has already been unmounted.
// We can't schedule any follow up work for the root because the fiber is already unmounted,
// but we can still call the log-only boundary so the error isn't swallowed.
//
// TODO This is only a temporary bandaid for the old reconciler fork.
// We can delete this special case once the new fork is merged.
if (
typeof instance.componentDidCatch === 'function' &&
!isAlreadyFailedLegacyErrorBoundary(instance)
) {
try {
instance.componentDidCatch(error, errorInfo);
} catch (errorToIgnore) {
// TODO Ignore this error? Rethrow it?
// This is kind of an edge case.
}
}
}
return;
}
@@ -2353,388 +2353,6 @@ describe('ReactHooksWithNoopRenderer', () => {
expect(ReactNoop.getChildren()).toEqual([]);
});
describe('errors thrown in passive destroy function within unmounted trees', () => {
let BrokenUseEffectCleanup;
let ErrorBoundary;
let DerivedStateOnlyErrorBoundary;
let LogOnlyErrorBoundary;
beforeEach(() => {
BrokenUseEffectCleanup = function() {
useEffect(() => {
Scheduler.unstable_yieldValue('BrokenUseEffectCleanup useEffect');
return () => {
Scheduler.unstable_yieldValue(
'BrokenUseEffectCleanup useEffect destroy',
);
throw new Error('Expected error');
};
}, []);
return 'inner child';
};
ErrorBoundary = class extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Scheduler.unstable_yieldValue(
`ErrorBoundary static getDerivedStateFromError`,
);
return {error};
}
componentDidCatch(error, info) {
Scheduler.unstable_yieldValue(`ErrorBoundary componentDidCatch`);
}
render() {
if (this.state.error) {
Scheduler.unstable_yieldValue('ErrorBoundary render error');
return <span prop="ErrorBoundary fallback" />;
}
Scheduler.unstable_yieldValue('ErrorBoundary render success');
return this.props.children || null;
}
};
DerivedStateOnlyErrorBoundary = class extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Scheduler.unstable_yieldValue(
`DerivedStateOnlyErrorBoundary static getDerivedStateFromError`,
);
return {error};
}
render() {
if (this.state.error) {
Scheduler.unstable_yieldValue(
'DerivedStateOnlyErrorBoundary render error',
);
return <span prop="DerivedStateOnlyErrorBoundary fallback" />;
}
Scheduler.unstable_yieldValue(
'DerivedStateOnlyErrorBoundary render success',
);
return this.props.children || null;
}
};
LogOnlyErrorBoundary = class extends React.Component {
componentDidCatch(error, info) {
Scheduler.unstable_yieldValue(
`LogOnlyErrorBoundary componentDidCatch`,
);
}
render() {
Scheduler.unstable_yieldValue(`LogOnlyErrorBoundary render`);
return this.props.children || null;
}
};
});
// @gate old
it('should call componentDidCatch() for the nearest unmounted log-only boundary', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<LogOnlyErrorBoundary>
<BrokenUseEffectCleanup />
</LogOnlyErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={true} />
</ErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'LogOnlyErrorBoundary render',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={false} />
</ErrorBoundary>,
);
expect(Scheduler).toFlushAndYieldThrough([
'ErrorBoundary render success',
]);
});
expect(Scheduler).toHaveYielded([
'BrokenUseEffectCleanup useEffect destroy',
'LogOnlyErrorBoundary componentDidCatch',
]);
});
// @gate old
it('should call componentDidCatch() for the nearest unmounted logging-capable boundary', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<ErrorBoundary>
<BrokenUseEffectCleanup />
</ErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={true} />
</ErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={false} />
</ErrorBoundary>,
);
expect(Scheduler).toFlushAndYieldThrough([
'ErrorBoundary render success',
]);
});
expect(Scheduler).toHaveYielded([
'BrokenUseEffectCleanup useEffect destroy',
'ErrorBoundary componentDidCatch',
]);
});
// @gate old
it('should not call getDerivedStateFromError for unmounted error boundaries', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<ErrorBoundary>
<BrokenUseEffectCleanup />
</ErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(<Conditional showChildren={true} />);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(<Conditional showChildren={false} />);
});
expect(Scheduler).toHaveYielded([
'BrokenUseEffectCleanup useEffect destroy',
'ErrorBoundary componentDidCatch',
]);
});
// @gate old
it('should not throw if there are no unmounted logging-capable boundaries to call', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<DerivedStateOnlyErrorBoundary>
<BrokenUseEffectCleanup />
</DerivedStateOnlyErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(<Conditional showChildren={true} />);
});
expect(Scheduler).toHaveYielded([
'DerivedStateOnlyErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(<Conditional showChildren={false} />);
});
expect(Scheduler).toHaveYielded([
'BrokenUseEffectCleanup useEffect destroy',
]);
});
// @gate new
it('should use the nearest still-mounted boundary if there are no unmounted boundaries', () => {
act(() => {
ReactNoop.render(
<LogOnlyErrorBoundary>
<BrokenUseEffectCleanup />
</LogOnlyErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'LogOnlyErrorBoundary render',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(<LogOnlyErrorBoundary />);
});
expect(Scheduler).toHaveYielded([
'LogOnlyErrorBoundary render',
'BrokenUseEffectCleanup useEffect destroy',
'LogOnlyErrorBoundary componentDidCatch',
]);
});
// @gate new
it('should skip unmounted boundaries and use the nearest still-mounted boundary', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<ErrorBoundary>
<BrokenUseEffectCleanup />
</ErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(
<LogOnlyErrorBoundary>
<Conditional showChildren={true} />
</LogOnlyErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'LogOnlyErrorBoundary render',
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(
<LogOnlyErrorBoundary>
<Conditional showChildren={false} />
</LogOnlyErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'LogOnlyErrorBoundary render',
'BrokenUseEffectCleanup useEffect destroy',
'LogOnlyErrorBoundary componentDidCatch',
]);
});
// @gate new
it('should call getDerivedStateFromError in the nearest still-mounted boundary', () => {
function Conditional({showChildren}) {
if (showChildren) {
return <BrokenUseEffectCleanup />;
} else {
return null;
}
}
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={true} />
</ErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
act(() => {
ReactNoop.render(
<ErrorBoundary>
<Conditional showChildren={false} />
</ErrorBoundary>,
);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect destroy',
'ErrorBoundary static getDerivedStateFromError',
'ErrorBoundary render error',
'ErrorBoundary componentDidCatch',
]);
expect(ReactNoop.getChildren()).toEqual([
span('ErrorBoundary fallback'),
]);
});
// @gate new
it('should rethrow error if there are no still-mounted boundaries', () => {
function Conditional({showChildren}) {
if (showChildren) {
return (
<ErrorBoundary>
<BrokenUseEffectCleanup />
</ErrorBoundary>
);
} else {
return null;
}
}
act(() => {
ReactNoop.render(<Conditional showChildren={true} />);
});
expect(Scheduler).toHaveYielded([
'ErrorBoundary render success',
'BrokenUseEffectCleanup useEffect',
]);
expect(() => {
act(() => {
ReactNoop.render(<Conditional showChildren={false} />);
});
}).toThrow('Expected error');
expect(Scheduler).toHaveYielded([
'BrokenUseEffectCleanup useEffect destroy',
]);
expect(ReactNoop.getChildren()).toEqual([]);
});
});
it('calls passive effect destroy functions for memoized components', () => {
const Wrapper = ({children}) => children;
function Child() {
@@ -2971,85 +2589,6 @@ describe('ReactHooksWithNoopRenderer', () => {
'Mount normal [current: 1]',
]);
});
// @gate skipUnmountedBoundaries
it('catches errors thrown in useLayoutEffect', () => {
class ErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Scheduler.unstable_yieldValue(
`ErrorBoundary static getDerivedStateFromError`,
);
return {error};
}
render() {
const {children, id, fallbackID} = this.props;
const {error} = this.state;
if (error) {
Scheduler.unstable_yieldValue(`${id} render error`);
return <Component id={fallbackID} />;
}
Scheduler.unstable_yieldValue(`${id} render success`);
return children || null;
}
}
function Component({id}) {
Scheduler.unstable_yieldValue('Component render ' + id);
return <span prop={id} />;
}
function BrokenLayoutEffectDestroy() {
useLayoutEffect(() => {
return () => {
Scheduler.unstable_yieldValue(
'BrokenLayoutEffectDestroy useLayoutEffect destroy',
);
throw Error('Expected');
};
}, []);
Scheduler.unstable_yieldValue('BrokenLayoutEffectDestroy render');
return <span prop="broken" />;
}
ReactNoop.render(
<ErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
<ErrorBoundary id="InnerBoundary" fallbackID="InnerFallback">
<BrokenLayoutEffectDestroy />
</ErrorBoundary>
</ErrorBoundary>,
);
expect(Scheduler).toFlushAndYield([
'OuterBoundary render success',
'Component render sibling',
'InnerBoundary render success',
'BrokenLayoutEffectDestroy render',
]);
expect(ReactNoop.getChildren()).toEqual([
span('sibling'),
span('broken'),
]);
ReactNoop.render(
<ErrorBoundary id="OuterBoundary" fallbackID="OuterFallback">
<Component id="sibling" />
</ErrorBoundary>,
);
// React should skip over the unmounting boundary and find the nearest still-mounted boundary.
expect(Scheduler).toFlushAndYield([
'OuterBoundary render success',
'Component render sibling',
'BrokenLayoutEffectDestroy useLayoutEffect destroy',
'ErrorBoundary static getDerivedStateFromError',
'OuterBoundary render error',
'Component render OuterFallback',
]);
expect(ReactNoop.getChildren()).toEqual([span('OuterFallback')]);
});
});
describe('useCallback', () => {
@@ -961,7 +961,6 @@ describe('ReactIncrementalErrorHandling', () => {
expect(Scheduler).toFlushAndYield(['Foo']);
});
// @gate skipUnmountedBoundaries
it('should not attempt to recover an unmounting error boundary', () => {
class Parent extends React.Component {
componentWillUnmount() {
@@ -993,17 +992,12 @@ describe('ReactIncrementalErrorHandling', () => {
ReactNoop.render(<Parent />);
expect(Scheduler).toFlushWithoutYielding();
// Because the error boundary is also unmounting,
// an error in ThrowsOnUnmount should be rethrown.
expect(() => {
ReactNoop.render(null);
expect(Scheduler).toFlushAndYield([
'Parent componentWillUnmount',
'ThrowsOnUnmount componentWillUnmount',
]);
}).toThrow('unmount error');
ReactNoop.render(null);
expect(Scheduler).toFlushAndYield([
// Parent unmounts before the error is thrown.
'Parent componentWillUnmount',
'ThrowsOnUnmount componentWillUnmount',
]);
ReactNoop.render(<Parent />);
});
-6
View File
@@ -91,12 +91,6 @@ export const enableComponentStackLocations = true;
export const enableNewReconciler = false;
// Errors that are thrown while unmounting (or after in the case of passive effects)
// should bypass any error boundaries that are also unmounting (or have unmounted)
// and be handled by the nearest still-mounted boundary.
// If there are no still-mounted boundaries, the errors should be rethrown.
export const skipUnmountedBoundaries = false;
// --------------------------
// Future APIs to be deprecated
// --------------------------
@@ -42,7 +42,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = false;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = false;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = false;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = false;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -41,7 +41,6 @@ export const warnAboutSpreadingKeyToJSX = false;
export const enableComponentStackLocations = true;
export const enableLegacyFBSupport = !__EXPERIMENTAL__;
export const enableFilterEmptyStringAttributesDOM = false;
export const skipUnmountedBoundaries = __EXPERIMENTAL__;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
@@ -18,7 +18,6 @@ export const disableInputAttributeSyncing = __VARIANT__;
export const enableFilterEmptyStringAttributesDOM = __VARIANT__;
export const enableLegacyFBSupport = __VARIANT__;
export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
export const skipUnmountedBoundaries = __VARIANT__;
// Enable this flag to help with concurrent mode debugging.
// It logs information to the console about React scheduling, rendering, and commit phases.
@@ -26,7 +26,6 @@ export const {
deferRenderPhaseUpdateToNextBatch,
decoupleUpdatePriorityFromScheduler,
enableDebugTracing,
skipUnmountedBoundaries,
enableDoubleInvokingEffects,
enableUseRefAccessWarning,
} = dynamicFeatureFlags;