mirror of
https://github.com/facebook/react.git
synced 2026-02-26 02:54:59 +00:00
[Fiber] Avoid duplicate debug info for array children (#35733)
This commit is contained in:
committed by
GitHub
parent
272441a9ad
commit
eab523e2a9
@@ -2820,7 +2820,8 @@ describe('ReactFlight', () => {
|
||||
]
|
||||
: undefined,
|
||||
);
|
||||
expect(getDebugInfo(thirdPartyChildren[2])).toEqual(
|
||||
const fragment = thirdPartyChildren[2];
|
||||
expect(getDebugInfo(fragment)).toEqual(
|
||||
__DEV__
|
||||
? [
|
||||
{time: gate(flags => flags.enableAsyncDebugInfo) ? 54 : 22},
|
||||
@@ -2835,6 +2836,9 @@ describe('ReactFlight', () => {
|
||||
]
|
||||
: undefined,
|
||||
);
|
||||
expect(getDebugInfo(fragment.props.children[0])).toEqual(
|
||||
__DEV__ ? null : undefined,
|
||||
);
|
||||
ReactNoop.render(result);
|
||||
});
|
||||
|
||||
@@ -2847,6 +2851,61 @@ describe('ReactFlight', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves debug info for keyed Fragment', async () => {
|
||||
function App() {
|
||||
return ReactServer.createElement(
|
||||
ReactServer.Fragment,
|
||||
{key: 'app'},
|
||||
ReactServer.createElement('h1', null, 'App'),
|
||||
ReactServer.createElement('div', null, 'Child'),
|
||||
);
|
||||
}
|
||||
|
||||
const transport = ReactNoopFlightServer.render(
|
||||
ReactServer.createElement(
|
||||
ReactServer.Fragment,
|
||||
null,
|
||||
ReactServer.createElement('link', {key: 'styles'}),
|
||||
ReactServer.createElement(App, null),
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
const root = await ReactNoopFlightClient.read(transport);
|
||||
|
||||
const fragment = root[1];
|
||||
expect(getDebugInfo(fragment)).toEqual(
|
||||
__DEV__
|
||||
? [
|
||||
{time: 12},
|
||||
{
|
||||
name: 'App',
|
||||
env: 'Server',
|
||||
key: null,
|
||||
stack: ' in Object.<anonymous> (at **)',
|
||||
props: {},
|
||||
},
|
||||
{time: 13},
|
||||
]
|
||||
: undefined,
|
||||
);
|
||||
// Making sure debug info doesn't get added multiple times on Fragment children
|
||||
expect(getDebugInfo(fragment[0])).toEqual(__DEV__ ? null : undefined);
|
||||
const fragmentChild = fragment[0].props.children[0];
|
||||
expect(getDebugInfo(fragmentChild)).toEqual(__DEV__ ? null : undefined);
|
||||
|
||||
ReactNoop.render(root);
|
||||
});
|
||||
|
||||
expect(ReactNoop).toMatchRenderedOutput(
|
||||
<>
|
||||
<link />
|
||||
<h1>App</h1>
|
||||
<div>Child</div>
|
||||
</>,
|
||||
);
|
||||
});
|
||||
|
||||
// @gate enableAsyncIterableChildren && enableComponentPerformanceTrack
|
||||
it('preserves debug info for server-to-server pass through of async iterables', async () => {
|
||||
let resolve;
|
||||
|
||||
@@ -2827,6 +2827,40 @@ describe('Store', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
// @reactVersion >= 19.0
|
||||
it('does not duplicate Server Component parents in keyed Fragments', async () => {
|
||||
// TODO: Use an actual Flight renderer.
|
||||
// See ReactFlight-test for the produced JSX from Flight.
|
||||
function ClientComponent() {
|
||||
return null;
|
||||
}
|
||||
// This used to be a keyed Fragment on the Server.
|
||||
const children = [<ClientComponent key="app" />];
|
||||
children._debugInfo = [
|
||||
{time: 12},
|
||||
{
|
||||
name: 'App',
|
||||
env: 'Server',
|
||||
key: null,
|
||||
stack: ' in Object.<anonymous> (at **)',
|
||||
props: {},
|
||||
},
|
||||
{time: 13},
|
||||
];
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOMClient.createRoot(container);
|
||||
await actAsync(() => {
|
||||
root.render([children]);
|
||||
});
|
||||
|
||||
expect(store).toMatchInlineSnapshot(`
|
||||
[root]
|
||||
▾ <App> [Server]
|
||||
<ClientComponent key="app">
|
||||
`);
|
||||
});
|
||||
|
||||
// @reactVersion >= 17.0
|
||||
it('can reconcile Suspense in fallback positions', async () => {
|
||||
let resolveFallback;
|
||||
|
||||
13
packages/react-reconciler/src/ReactChildFiber.js
vendored
13
packages/react-reconciler/src/ReactChildFiber.js
vendored
@@ -789,6 +789,7 @@ function createChildReconciler(
|
||||
// We treat the parent as the owner for stack purposes.
|
||||
created._debugOwner = returnFiber;
|
||||
created._debugTask = returnFiber._debugTask;
|
||||
// Make sure to not push again when handling the Fragment child.
|
||||
const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
|
||||
created._debugInfo = currentDebugInfo;
|
||||
currentDebugInfo = prevDebugInfo;
|
||||
@@ -1915,26 +1916,26 @@ function createChildReconciler(
|
||||
}
|
||||
|
||||
if (isArray(newChild)) {
|
||||
const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
|
||||
// We created a Fragment for this child with the debug info.
|
||||
// No need to push again.
|
||||
const firstChild = reconcileChildrenArray(
|
||||
returnFiber,
|
||||
currentFirstChild,
|
||||
newChild,
|
||||
lanes,
|
||||
);
|
||||
currentDebugInfo = prevDebugInfo;
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
if (getIteratorFn(newChild)) {
|
||||
const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
|
||||
// We created a Fragment for this child with the debug info.
|
||||
// No need to push again.
|
||||
const firstChild = reconcileChildrenIteratable(
|
||||
returnFiber,
|
||||
currentFirstChild,
|
||||
newChild,
|
||||
lanes,
|
||||
);
|
||||
currentDebugInfo = prevDebugInfo;
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
@@ -1942,14 +1943,14 @@ function createChildReconciler(
|
||||
enableAsyncIterableChildren &&
|
||||
typeof newChild[ASYNC_ITERATOR] === 'function'
|
||||
) {
|
||||
const prevDebugInfo = pushDebugInfo(newChild._debugInfo);
|
||||
// We created a Fragment for this child with the debug info.
|
||||
// No need to push again.
|
||||
const firstChild = reconcileChildrenAsyncIteratable(
|
||||
returnFiber,
|
||||
currentFirstChild,
|
||||
newChild,
|
||||
lanes,
|
||||
);
|
||||
currentDebugInfo = prevDebugInfo;
|
||||
return firstChild;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user