mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[Flight] Allow Temporary References to be awaited (#34084)
Fixes #33534. `.then` method can be tested when you await a value that's not a Promise. For regular Client References we have a way to mark those as "async" and yield a reference to the unwrapped value in case it's a Promise on the Client. However, the realization is that we never serialize Promises as opaque when passed from the client to the server. If a Promise is passed, then it would've been deserialized as a Promise (while still registered as a temporary reference) and not one of these Proxy objects. Technically it could be a non-function value on the client which would be wrong but you're not supposed to dot into it in the first place. So we can just assume it's `undefined`.
This commit is contained in:
parent
1d163962b2
commit
c499adf8c8
|
|
@ -438,6 +438,50 @@ describe('ReactFlightDOMReply', () => {
|
||||||
expect(response.obj).toBe(obj);
|
expect(response.obj).toBe(obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can return an opaque object through an async function', async () => {
|
||||||
|
function fn() {
|
||||||
|
return 'this is a client function';
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = [fn];
|
||||||
|
|
||||||
|
const temporaryReferences =
|
||||||
|
ReactServerDOMClient.createTemporaryReferenceSet();
|
||||||
|
const body = await ReactServerDOMClient.encodeReply(args, {
|
||||||
|
temporaryReferences,
|
||||||
|
});
|
||||||
|
|
||||||
|
const temporaryReferencesServer =
|
||||||
|
ReactServerDOMServer.createTemporaryReferenceSet();
|
||||||
|
const serverPayload = await ReactServerDOMServer.decodeReply(
|
||||||
|
body,
|
||||||
|
webpackServerMap,
|
||||||
|
{temporaryReferences: temporaryReferencesServer},
|
||||||
|
);
|
||||||
|
|
||||||
|
async function action(arg) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stream = await serverAct(() =>
|
||||||
|
ReactServerDOMServer.renderToReadableStream(
|
||||||
|
{
|
||||||
|
result: action.apply(null, serverPayload),
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{temporaryReferences: temporaryReferencesServer},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const response = await ReactServerDOMClient.createFromReadableStream(
|
||||||
|
stream,
|
||||||
|
{
|
||||||
|
temporaryReferences,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await response.result).toBe(fn);
|
||||||
|
});
|
||||||
|
|
||||||
it('should supports streaming ReadableStream with objects', async () => {
|
it('should supports streaming ReadableStream with objects', async () => {
|
||||||
let controller1;
|
let controller1;
|
||||||
let controller2;
|
let controller2;
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,12 @@ const proxyHandlers = {
|
||||||
`Instead, you can export a Client Component wrapper ` +
|
`Instead, you can export a Client Component wrapper ` +
|
||||||
`that itself renders a Client Context Provider.`,
|
`that itself renders a Client Context Provider.`,
|
||||||
);
|
);
|
||||||
// Allow returning a temporary reference from an async function
|
|
||||||
case 'then':
|
case 'then':
|
||||||
|
// Allow returning a temporary reference from an async function
|
||||||
|
// Unlike regular Client References, a Promise would never have been serialized as
|
||||||
|
// an opaque Temporary Reference, but instead would have been serialized as a
|
||||||
|
// Promise on the server and so doesn't hit this path. So we can assume this wasn't
|
||||||
|
// a Promise on the client.
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @emails react-core
|
|
||||||
* @jest-environment node
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
let ReactFlightServerTemporaryReferences;
|
|
||||||
|
|
||||||
describe('ReactFlightServerTemporaryReferences', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetModules();
|
|
||||||
ReactFlightServerTemporaryReferences = require('react-server/src/ReactFlightServerTemporaryReferences');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can return a temporary reference from an async function', async () => {
|
|
||||||
const temporaryReferenceSet =
|
|
||||||
ReactFlightServerTemporaryReferences.createTemporaryReferenceSet();
|
|
||||||
const temporaryReference =
|
|
||||||
ReactFlightServerTemporaryReferences.createTemporaryReference(
|
|
||||||
temporaryReferenceSet,
|
|
||||||
'test',
|
|
||||||
);
|
|
||||||
|
|
||||||
async function foo() {
|
|
||||||
return temporaryReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
await expect(foo()).resolves.toBe(temporaryReference);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
Reference in New Issue
Block a user