mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[Flight] Fix debug info leaking to outer handler (#34081)
The `waitForReference` call for debug info can trigger inside a
different object's initializingHandler. In that case, we can get
confused by which one is the root object.
We have this special case to detect if the initializing handler's object
is `null` and we have an empty string key, then we should replace the
root object's value with the resolved value.
52612a7cbd/packages/react-client/src/ReactFlightClient.js (L1374)
However, if the initializing handler actually should have the value
`null` then we might get confused by this and replace it with the
resolved value from a debug object. This fixes it by just using a
non-empty string as the key for the waitForReference on debug value
since we're not going to use it anyway.
It used to be impossible to get into this state since a `null` value at
the root couldn't have any reference inside itself but now the debug
info for a `null` value can have outstanding references.
However, a better fix might be using a placeholder marker object instead
of null or better yet ensuring that we know which root we're
initializing in the debug model.
This commit is contained in:
parent
52612a7cbd
commit
538ac7ae4b
|
|
@ -879,7 +879,7 @@ function initializeDebugChunk(
|
|||
waitForReference(
|
||||
debugChunk,
|
||||
{}, // noop, since we'll have already added an entry to debug info
|
||||
'', // noop
|
||||
'debug', // noop, but we need it to not be empty string since that indicates the root object
|
||||
response,
|
||||
initializeDebugInfo,
|
||||
[''], // path
|
||||
|
|
|
|||
|
|
@ -1915,4 +1915,57 @@ describe('ReactFlightDOMEdge', () => {
|
|||
expect(ownerStack).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('can pass an async import that resolves later as a prop to a null component', async () => {
|
||||
let resolveClientComponentChunk;
|
||||
const client = clientExports(
|
||||
{
|
||||
foo: 'bar',
|
||||
},
|
||||
'42',
|
||||
'/test.js',
|
||||
new Promise(resolve => (resolveClientComponentChunk = resolve)),
|
||||
);
|
||||
|
||||
function ServerComponent(props) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<ServerComponent client={client} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const stream = await serverAct(() =>
|
||||
passThrough(
|
||||
ReactServerDOMServer.renderToReadableStream(<App />, webpackMap),
|
||||
),
|
||||
);
|
||||
|
||||
// Parsing the root blocks because the module hasn't loaded yet
|
||||
const response = ReactServerDOMClient.createFromReadableStream(stream, {
|
||||
serverConsumerManifest: {
|
||||
moduleMap: null,
|
||||
moduleLoading: null,
|
||||
},
|
||||
});
|
||||
|
||||
function ClientRoot() {
|
||||
return use(response);
|
||||
}
|
||||
|
||||
// Initialize to be blocked.
|
||||
response.then(() => {});
|
||||
// Unblock.
|
||||
resolveClientComponentChunk();
|
||||
|
||||
const ssrStream = await serverAct(() =>
|
||||
ReactDOMServer.renderToReadableStream(<ClientRoot />),
|
||||
);
|
||||
const result = await readResult(ssrStream);
|
||||
expect(result).toEqual('<div></div>');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user