mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Materialize the tree ID when ViewTransition name=auto consumes one (#32651)
ViewTransition uses the `useId` algorithm to auto-assign names. This ensures that we could animate between SSR content and client content by ensuring that the names line up. However, I missed that we need to bump the id (materialize it) when we do that. This is what function components do if they use one or more `useId()`. This caused duplicate names when two ViewTransitions were nested without any siblings since they would share name.
This commit is contained in:
parent
ca02c4bb40
commit
9fde224a53
|
|
@ -4,6 +4,7 @@ import React, {
|
|||
unstable_useSwipeTransition as useSwipeTransition,
|
||||
useEffect,
|
||||
useState,
|
||||
useId,
|
||||
} from 'react';
|
||||
|
||||
import SwipeRecognizer from './SwipeRecognizer';
|
||||
|
|
@ -39,6 +40,11 @@ function Component() {
|
|||
);
|
||||
}
|
||||
|
||||
function Id() {
|
||||
// This is just testing that Id inside a ViewTransition can hydrate correctly.
|
||||
return <span id={useId()} />;
|
||||
}
|
||||
|
||||
export default function Page({url, navigate}) {
|
||||
const [renderedUrl, startGesture] = useSwipeTransition('/?a', url, '/?b');
|
||||
const show = renderedUrl === '/?b';
|
||||
|
|
@ -77,8 +83,12 @@ export default function Page({url, navigate}) {
|
|||
</button>
|
||||
<ViewTransition className="none">
|
||||
<div>
|
||||
<ViewTransition className={transitions['slide-on-nav']}>
|
||||
<h1>{!show ? 'A' : 'B'}</h1>
|
||||
<ViewTransition>
|
||||
<div>
|
||||
<ViewTransition className={transitions['slide-on-nav']}>
|
||||
<h1>{!show ? 'A' : 'B'}</h1>
|
||||
</ViewTransition>
|
||||
</div>
|
||||
</ViewTransition>
|
||||
<ViewTransition
|
||||
className={{
|
||||
|
|
@ -102,7 +112,9 @@ export default function Page({url, navigate}) {
|
|||
{show ? <div>hello{exclamation}</div> : <section>Loading</section>}
|
||||
</ViewTransition>
|
||||
<p>scroll me</p>
|
||||
<p></p>
|
||||
<p>
|
||||
<Id />
|
||||
</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
|
|
|
|||
|
|
@ -3298,6 +3298,9 @@ function updateViewTransition(
|
|||
// to client rendered content. If we don't end up using that we could just assign an incremeting
|
||||
// counter in the commit phase instead.
|
||||
assignViewTransitionAutoName(pendingProps, instance);
|
||||
if (getIsHydrating()) {
|
||||
pushMaterializedTreeId(workInProgress);
|
||||
}
|
||||
}
|
||||
if (current !== null && current.memoizedProps.name !== pendingProps.name) {
|
||||
// If the name changes, we schedule a ref effect to create a new ref instance.
|
||||
|
|
|
|||
33
packages/react-server/src/ReactFizzServer.js
vendored
33
packages/react-server/src/ReactFizzServer.js
vendored
|
|
@ -2211,6 +2211,34 @@ function renderOffscreen(
|
|||
}
|
||||
}
|
||||
|
||||
function renderViewTransition(
|
||||
request: Request,
|
||||
task: Task,
|
||||
keyPath: KeyNode,
|
||||
props: Object,
|
||||
) {
|
||||
const prevKeyPath = task.keyPath;
|
||||
task.keyPath = keyPath;
|
||||
if (props.name != null && props.name !== 'auto') {
|
||||
renderNodeDestructive(request, task, props.children, -1);
|
||||
} else {
|
||||
// This will be auto-assigned a name which claims a "useId" slot.
|
||||
// This component materialized an id. We treat this as its own level, with
|
||||
// a single "child" slot.
|
||||
const prevTreeContext = task.treeContext;
|
||||
const totalChildren = 1;
|
||||
const index = 0;
|
||||
// Modify the id context. Because we'll need to reset this if something
|
||||
// suspends or errors, we'll use the non-destructive render path.
|
||||
task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
|
||||
renderNode(request, task, props.children, -1);
|
||||
// Like the other contexts, this does not need to be in a finally block
|
||||
// because renderNode takes care of unwinding the stack.
|
||||
task.treeContext = prevTreeContext;
|
||||
}
|
||||
task.keyPath = prevKeyPath;
|
||||
}
|
||||
|
||||
function renderElement(
|
||||
request: Request,
|
||||
task: Task,
|
||||
|
|
@ -2267,10 +2295,7 @@ function renderElement(
|
|||
}
|
||||
case REACT_VIEW_TRANSITION_TYPE: {
|
||||
if (enableViewTransition) {
|
||||
const prevKeyPath = task.keyPath;
|
||||
task.keyPath = keyPath;
|
||||
renderNodeDestructive(request, task, props.children, -1);
|
||||
task.keyPath = prevKeyPath;
|
||||
renderViewTransition(request, task, keyPath, props);
|
||||
return;
|
||||
}
|
||||
// Fallthrough
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user