Skip to content

Commit 3710c4d

Browse files
authored
Prevent errors from comment node roots with enableViewTransition (facebook#33205)
We have many cases internally where the `containerInstance` resolves to a comment node. `restoreRootViewTransitionName` is called when `enableViewTransition` is on, even without introducing a `<ViewTransition />`. So that means it can crash pages because `containerInstance.style` is `undefined` just by turning on the flag. This skips cancel/restore of root view transition name if a comment node is the root.
1 parent 2388481 commit 3710c4d

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,19 @@ export function cancelRootViewTransitionName(rootContainer: Container): void {
15491549
rootContainer.nodeType === DOCUMENT_NODE
15501550
? (rootContainer: any).documentElement
15511551
: rootContainer.ownerDocument.documentElement;
1552+
1553+
if (
1554+
!disableCommentsAsDOMContainers &&
1555+
rootContainer.nodeType === COMMENT_NODE
1556+
) {
1557+
if (__DEV__) {
1558+
console.warn(
1559+
'Cannot cancel root view transition on a comment node. All view transitions will be globally scoped.',
1560+
);
1561+
}
1562+
return;
1563+
}
1564+
15521565
if (
15531566
documentElement !== null &&
15541567
// $FlowFixMe[prop-missing]
@@ -1593,8 +1606,16 @@ export function restoreRootViewTransitionName(rootContainer: Container): void {
15931606
// clone the whole document outside of the React too.
15941607
containerInstance = (rootContainer: any);
15951608
}
1596-
// $FlowFixMe[prop-missing]
1597-
if (containerInstance.style.viewTransitionName === 'root') {
1609+
if (
1610+
!disableCommentsAsDOMContainers &&
1611+
containerInstance.nodeType === COMMENT_NODE
1612+
) {
1613+
return;
1614+
}
1615+
if (
1616+
// $FlowFixMe[prop-missing]
1617+
containerInstance.style.viewTransitionName === 'root'
1618+
) {
15981619
// If we moved the root view transition name to the container in a gesture
15991620
// we need to restore it now.
16001621
containerInstance.style.viewTransitionName = '';
@@ -1708,6 +1729,13 @@ export function cloneRootViewTransitionContainer(
17081729
containerInstance = (rootContainer: any).body;
17091730
} else if (rootContainer.nodeName === 'HTML') {
17101731
containerInstance = (rootContainer.ownerDocument.body: any);
1732+
} else if (
1733+
!disableCommentsAsDOMContainers &&
1734+
rootContainer.nodeType === COMMENT_NODE
1735+
) {
1736+
throw new Error(
1737+
'Cannot use a startGestureTransition() with a comment node root.',
1738+
);
17111739
} else {
17121740
// If the container is not the whole document, then we ideally should probably
17131741
// clone the whole document outside of the React too.

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ export let shouldFireAfterActiveInstanceBlur: boolean = false;
306306
let viewTransitionContextChanged: boolean = false;
307307
let inUpdateViewTransition: boolean = false;
308308
let rootViewTransitionAffected: boolean = false;
309+
let rootViewTransitionNameCanceled: boolean = false;
309310

310311
function isHydratingParent(current: Fiber, finishedWork: Fiber): boolean {
311312
if (finishedWork.tag === ActivityComponent) {
@@ -2737,6 +2738,7 @@ function commitAfterMutationEffectsOnFiber(
27372738
switch (finishedWork.tag) {
27382739
case HostRoot: {
27392740
viewTransitionContextChanged = false;
2741+
rootViewTransitionNameCanceled = false;
27402742
pushViewTransitionCancelableScope();
27412743
recursivelyTraverseAfterMutationEffects(root, finishedWork, lanes);
27422744
if (!viewTransitionContextChanged && !rootViewTransitionAffected) {
@@ -2755,6 +2757,7 @@ function commitAfterMutationEffectsOnFiber(
27552757
}
27562758
// We also cancel the root itself.
27572759
cancelRootViewTransitionName(root.containerInfo);
2760+
rootViewTransitionNameCanceled = true;
27582761
}
27592762
popViewTransitionCancelableScope(null);
27602763
break;
@@ -3613,7 +3616,7 @@ function commitPassiveMountOnFiber(
36133616
}
36143617

36153618
if (isViewTransitionEligible) {
3616-
if (supportsMutation) {
3619+
if (supportsMutation && rootViewTransitionNameCanceled) {
36173620
restoreRootViewTransitionName(finishedRoot.containerInfo);
36183621
}
36193622
}

scripts/error-codes/codes.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,5 +544,6 @@
544544
"556": "Expected prepareToHydrateHostActivityInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.",
545545
"557": "Expected to have a hydrated activity instance. This error is likely caused by a bug in React. Please file an issue.",
546546
"558": "Client rendering an Activity suspended it again. This is a bug in React.",
547-
"559": "Expected to find a host node. This is a bug in React."
547+
"559": "Expected to find a host node. This is a bug in React.",
548+
"560": "Cannot use a startGestureTransition() with a comment node root."
548549
}

0 commit comments

Comments
 (0)