Skip to content

Commit 1d26103

Browse files
committed
Reenable JSX elements in Replies
1 parent 47f0715 commit 1d26103

File tree

2 files changed

+36
-23
lines changed

2 files changed

+36
-23
lines changed

packages/react-client/src/ReactFlightReplyClient.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,18 @@ export function processReply(
227227
switch ((value: any).$$typeof) {
228228
case REACT_ELEMENT_TYPE: {
229229
if (temporaryReferences === undefined) {
230-
throw new Error(
231-
'React Element cannot be passed to Server Functions from the Client without a ' +
232-
'temporary reference set. Pass a TemporaryReferenceSet to the options.' +
233-
(__DEV__ ? describeObjectForErrorMessage(parent, key) : ''),
234-
);
230+
const element: React$Element<any> = (value: any);
231+
// Serialize as a plain object with a symbol property
232+
// TODO: Consider if we should use a special encoding for this or restore a proper
233+
// element object on the server. E.g. we probably need the _store stuff in case it
234+
// is passed as a child. For now we assume it'll just be passed back to Flight.
235+
return {
236+
$$typeof: REACT_ELEMENT_TYPE,
237+
type: element.type,
238+
key: element.key,
239+
ref: element.ref,
240+
props: element.props,
241+
};
235242
}
236243
return serializeTemporaryReferenceID(
237244
writeTemporaryReference(temporaryReferences, value),

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -302,24 +302,6 @@ describe('ReactFlightDOMReply', () => {
302302
expect(await result2.lazy.value).toBe('Hello');
303303
});
304304

305-
it('errors when called with JSX by default', async () => {
306-
let error;
307-
try {
308-
await ReactServerDOMClient.encodeReply(<div />);
309-
} catch (x) {
310-
error = x;
311-
}
312-
expect(error).toEqual(
313-
expect.objectContaining({
314-
message: __DEV__
315-
? expect.stringContaining(
316-
'React Element cannot be passed to Server Functions from the Client without a temporary reference set.',
317-
)
318-
: expect.stringContaining(''),
319-
}),
320-
);
321-
});
322-
323305
it('can pass JSX through a round trip using temporary references', async () => {
324306
function Component() {
325307
return <div />;
@@ -377,4 +359,28 @@ describe('ReactFlightDOMReply', () => {
377359

378360
expect(response2.replied).toBe(Component);
379361
});
362+
363+
it('can pass a client JSX sent by the server back again', async () => {
364+
function Component() {
365+
return <div />;
366+
}
367+
368+
const ClientComponent = clientExports(Component);
369+
370+
const stream1 = ReactServerDOMServer.renderToReadableStream(
371+
<ClientComponent />,
372+
webpackMap,
373+
);
374+
const response1 =
375+
await ReactServerDOMClient.createFromReadableStream(stream1);
376+
377+
const body = await ReactServerDOMClient.encodeReply(response1);
378+
const serverPayload = await ReactServerDOMServer.decodeReply(body);
379+
380+
const stream2 = ReactServerDOMServer.renderToReadableStream(serverPayload);
381+
const response2 =
382+
await ReactServerDOMClient.createFromReadableStream(stream2);
383+
384+
expect(response2.type).toBe(Component);
385+
});
380386
});

0 commit comments

Comments
 (0)