Skip to content

Commit

Permalink
Don't let error boundaries catch errors during hydration (#28675)
Browse files Browse the repository at this point in the history
When an error boundary catches an error during hydration it'll try to
render the error state which will then try to hydrate that state,
causing hydration warnings.

When an error happens inside a Suspense boundary during hydration, we
instead let the boundary catch it and restart a client render from
there. However, when it's in the root we instead let it fail the root
and do the sync recovery pass. This didn't consider that we might hit an
error boundary first so this just skips the error boundary in that case.

We should probably instead let the root do a concurrent client render in
this same pass instead to unify with Suspense boundaries.

DiffTrain build for [5d4b758](5d4b758)
  • Loading branch information
sebmarkbage committed Mar 29, 2024
1 parent 120239f commit a180cdd
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 251 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2aed507a76a0b1524426c398897cbe47d80c51e5
5d4b7587da52dd81bc5c366b909c4511e2970cd1
3 changes: 1 addition & 2 deletions compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if (__DEV__) {
return self;
}

var ReactVersion = "19.0.0-www-classic-9a163259";
var ReactVersion = "19.0.0-www-classic-b8b7775c";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -15149,7 +15149,6 @@ if (__DEV__) {
}

case ClassComponent:
// Capture and retry
var errorInfo = value;
var ctor = workInProgress.type;
var instance = workInProgress.stateNode;
Expand Down
3 changes: 1 addition & 2 deletions compiled/facebook-www/ReactART-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if (__DEV__) {
return self;
}

var ReactVersion = "19.0.0-www-modern-58f8023b";
var ReactVersion = "19.0.0-www-modern-c4adbf64";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -14873,7 +14873,6 @@ if (__DEV__) {
}

case ClassComponent:
// Capture and retry
var errorInfo = value;
var ctor = workInProgress.type;
var instance = workInProgress.stateNode;
Expand Down
11 changes: 9 additions & 2 deletions compiled/facebook-www/ReactDOM-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -19939,7 +19939,14 @@ if (__DEV__) {
}

case ClassComponent:
// Capture and retry
if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) {
// If we're hydrating and got here, it means that we didn't find a suspense
// boundary above so it's a root error. In this case we shouldn't let the
// error boundary capture it because it'll just try to hydrate the error state.
// Instead we let it bubble to the root and let the recover pass handle it.
break;
} // Capture and retry

var errorInfo = value;
var ctor = workInProgress.type;
var instance = workInProgress.stateNode;
Expand Down Expand Up @@ -36351,7 +36358,7 @@ if (__DEV__) {
return root;
}

var ReactVersion = "19.0.0-www-classic-36b47fc1";
var ReactVersion = "19.0.0-www-classic-7d681296";

function createPortal$1(
children,
Expand Down
11 changes: 9 additions & 2 deletions compiled/facebook-www/ReactDOM-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -19861,7 +19861,14 @@ if (__DEV__) {
}

case ClassComponent:
// Capture and retry
if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) {
// If we're hydrating and got here, it means that we didn't find a suspense
// boundary above so it's a root error. In this case we shouldn't let the
// error boundary capture it because it'll just try to hydrate the error state.
// Instead we let it bubble to the root and let the recover pass handle it.
break;
} // Capture and retry

var errorInfo = value;
var ctor = workInProgress.type;
var instance = workInProgress.stateNode;
Expand Down Expand Up @@ -36199,7 +36206,7 @@ if (__DEV__) {
return root;
}

var ReactVersion = "19.0.0-www-modern-7787bbbe";
var ReactVersion = "19.0.0-www-modern-439124ba";

function createPortal$1(
children,
Expand Down
80 changes: 41 additions & 39 deletions compiled/facebook-www/ReactDOM-prod.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -5018,10 +5018,10 @@ function throwException(
),
wakeable === noopSuspenseyCommitThenable
? (value.flags |= 16384)
: ((returnFiber = value.updateQueue),
null === returnFiber
: ((sourceFiber = value.updateQueue),
null === sourceFiber
? (value.updateQueue = new Set([wakeable]))
: returnFiber.add(wakeable),
: sourceFiber.add(wakeable),
value.mode & 1 &&
attachPingListener(root, wakeable, rootRenderLanes)),
!1
Expand All @@ -5032,18 +5032,18 @@ function throwException(
(value.flags |= 65536),
wakeable === noopSuspenseyCommitThenable
? (value.flags |= 16384)
: ((returnFiber = value.updateQueue),
null === returnFiber
? ((returnFiber = {
: ((sourceFiber = value.updateQueue),
null === sourceFiber
? ((sourceFiber = {
transitions: null,
markerInstances: null,
retryQueue: new Set([wakeable])
}),
(value.updateQueue = returnFiber))
: ((sourceFiber = returnFiber.retryQueue),
null === sourceFiber
? (returnFiber.retryQueue = new Set([wakeable]))
: sourceFiber.add(wakeable)),
(value.updateQueue = sourceFiber))
: ((returnFiber = sourceFiber.retryQueue),
null === returnFiber
? (sourceFiber.retryQueue = new Set([wakeable]))
: returnFiber.add(wakeable)),
attachPingListener(root, wakeable, rootRenderLanes)),
!1
);
Expand Down Expand Up @@ -5099,31 +5099,33 @@ function throwException(
!1
);
case 1:
returnFiber = value;
sourceFiber = wakeable.type;
var instance = wakeable.stateNode;
if (
0 === (wakeable.flags & 128) &&
("function" === typeof sourceFiber.getDerivedStateFromError ||
(null !== instance &&
"function" === typeof instance.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(instance))))
)
return (
(wakeable.flags |= 65536),
(rootRenderLanes &= -rootRenderLanes),
(wakeable.lanes |= rootRenderLanes),
(rootRenderLanes = createClassErrorUpdate(rootRenderLanes)),
initializeClassErrorUpdate(
rootRenderLanes,
root,
wakeable,
returnFiber
),
enqueueCapturedUpdate(wakeable, rootRenderLanes),
!1
);
if (!(isHydrating && sourceFiber.mode & 1)) {
returnFiber = value;
var ctor = wakeable.type,
instance = wakeable.stateNode;
if (
0 === (wakeable.flags & 128) &&
("function" === typeof ctor.getDerivedStateFromError ||
(null !== instance &&
"function" === typeof instance.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(instance))))
)
return (
(wakeable.flags |= 65536),
(rootRenderLanes &= -rootRenderLanes),
(wakeable.lanes |= rootRenderLanes),
(rootRenderLanes = createClassErrorUpdate(rootRenderLanes)),
initializeClassErrorUpdate(
rootRenderLanes,
root,
wakeable,
returnFiber
),
enqueueCapturedUpdate(wakeable, rootRenderLanes),
!1
);
}
}
wakeable = wakeable.return;
} while (null !== wakeable);
Expand Down Expand Up @@ -17105,7 +17107,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1732 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "19.0.0-www-classic-64e7bfa1",
version: "19.0.0-www-classic-b1be4296",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2160 = {
Expand Down Expand Up @@ -17135,7 +17137,7 @@ var internals$jscomp$inline_2160 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-www-classic-64e7bfa1"
reconcilerVersion: "19.0.0-www-classic-b1be4296"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2161 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
Expand Down Expand Up @@ -17585,4 +17587,4 @@ exports.useFormState = function (action, initialState, permalink) {
exports.useFormStatus = function () {
return ReactCurrentDispatcher$2.current.useHostTransitionStatus();
};
exports.version = "19.0.0-www-classic-64e7bfa1";
exports.version = "19.0.0-www-classic-b1be4296";
80 changes: 41 additions & 39 deletions compiled/facebook-www/ReactDOM-prod.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -4902,10 +4902,10 @@ function throwException(
),
wakeable === noopSuspenseyCommitThenable
? (value.flags |= 16384)
: ((returnFiber = value.updateQueue),
null === returnFiber
: ((sourceFiber = value.updateQueue),
null === sourceFiber
? (value.updateQueue = new Set([wakeable]))
: returnFiber.add(wakeable),
: sourceFiber.add(wakeable),
value.mode & 1 &&
attachPingListener(root, wakeable, rootRenderLanes)),
!1
Expand All @@ -4916,18 +4916,18 @@ function throwException(
(value.flags |= 65536),
wakeable === noopSuspenseyCommitThenable
? (value.flags |= 16384)
: ((returnFiber = value.updateQueue),
null === returnFiber
? ((returnFiber = {
: ((sourceFiber = value.updateQueue),
null === sourceFiber
? ((sourceFiber = {
transitions: null,
markerInstances: null,
retryQueue: new Set([wakeable])
}),
(value.updateQueue = returnFiber))
: ((sourceFiber = returnFiber.retryQueue),
null === sourceFiber
? (returnFiber.retryQueue = new Set([wakeable]))
: sourceFiber.add(wakeable)),
(value.updateQueue = sourceFiber))
: ((returnFiber = sourceFiber.retryQueue),
null === returnFiber
? (sourceFiber.retryQueue = new Set([wakeable]))
: returnFiber.add(wakeable)),
attachPingListener(root, wakeable, rootRenderLanes)),
!1
);
Expand Down Expand Up @@ -4983,31 +4983,33 @@ function throwException(
!1
);
case 1:
returnFiber = value;
sourceFiber = wakeable.type;
var instance = wakeable.stateNode;
if (
0 === (wakeable.flags & 128) &&
("function" === typeof sourceFiber.getDerivedStateFromError ||
(null !== instance &&
"function" === typeof instance.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(instance))))
)
return (
(wakeable.flags |= 65536),
(rootRenderLanes &= -rootRenderLanes),
(wakeable.lanes |= rootRenderLanes),
(rootRenderLanes = createClassErrorUpdate(rootRenderLanes)),
initializeClassErrorUpdate(
rootRenderLanes,
root,
wakeable,
returnFiber
),
enqueueCapturedUpdate(wakeable, rootRenderLanes),
!1
);
if (!(isHydrating && sourceFiber.mode & 1)) {
returnFiber = value;
var ctor = wakeable.type,
instance = wakeable.stateNode;
if (
0 === (wakeable.flags & 128) &&
("function" === typeof ctor.getDerivedStateFromError ||
(null !== instance &&
"function" === typeof instance.componentDidCatch &&
(null === legacyErrorBoundariesThatAlreadyFailed ||
!legacyErrorBoundariesThatAlreadyFailed.has(instance))))
)
return (
(wakeable.flags |= 65536),
(rootRenderLanes &= -rootRenderLanes),
(wakeable.lanes |= rootRenderLanes),
(rootRenderLanes = createClassErrorUpdate(rootRenderLanes)),
initializeClassErrorUpdate(
rootRenderLanes,
root,
wakeable,
returnFiber
),
enqueueCapturedUpdate(wakeable, rootRenderLanes),
!1
);
}
}
wakeable = wakeable.return;
} while (null !== wakeable);
Expand Down Expand Up @@ -16619,7 +16621,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1693 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "19.0.0-www-modern-0a452e58",
version: "19.0.0-www-modern-44929488",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2122 = {
Expand Down Expand Up @@ -16649,7 +16651,7 @@ var internals$jscomp$inline_2122 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-www-modern-0a452e58"
reconcilerVersion: "19.0.0-www-modern-44929488"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2123 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
Expand Down Expand Up @@ -16952,4 +16954,4 @@ exports.useFormState = function (action, initialState, permalink) {
exports.useFormStatus = function () {
return ReactCurrentDispatcher$2.current.useHostTransitionStatus();
};
exports.version = "19.0.0-www-modern-0a452e58";
exports.version = "19.0.0-www-modern-44929488";
Loading

0 comments on commit a180cdd

Please sign in to comment.