Skip to content

Commit

Permalink
Reenable JSX elements in Replies
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Mar 21, 2024
1 parent 47f0715 commit 1d26103
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 23 deletions.
17 changes: 12 additions & 5 deletions packages/react-client/src/ReactFlightReplyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,18 @@ export function processReply(
switch ((value: any).$$typeof) {
case REACT_ELEMENT_TYPE: {
if (temporaryReferences === undefined) {
throw new Error(
'React Element cannot be passed to Server Functions from the Client without a ' +
'temporary reference set. Pass a TemporaryReferenceSet to the options.' +
(__DEV__ ? describeObjectForErrorMessage(parent, key) : ''),
);
const element: React$Element<any> = (value: any);
// Serialize as a plain object with a symbol property
// TODO: Consider if we should use a special encoding for this or restore a proper
// element object on the server. E.g. we probably need the _store stuff in case it
// is passed as a child. For now we assume it'll just be passed back to Flight.
return {
$$typeof: REACT_ELEMENT_TYPE,
type: element.type,
key: element.key,
ref: element.ref,
props: element.props,
};
}
return serializeTemporaryReferenceID(
writeTemporaryReference(temporaryReferences, value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,24 +302,6 @@ describe('ReactFlightDOMReply', () => {
expect(await result2.lazy.value).toBe('Hello');
});

it('errors when called with JSX by default', async () => {
let error;
try {
await ReactServerDOMClient.encodeReply(<div />);
} catch (x) {
error = x;
}
expect(error).toEqual(
expect.objectContaining({
message: __DEV__
? expect.stringContaining(
'React Element cannot be passed to Server Functions from the Client without a temporary reference set.',
)
: expect.stringContaining(''),
}),
);
});

it('can pass JSX through a round trip using temporary references', async () => {
function Component() {
return <div />;
Expand Down Expand Up @@ -377,4 +359,28 @@ describe('ReactFlightDOMReply', () => {

expect(response2.replied).toBe(Component);
});

it('can pass a client JSX sent by the server back again', async () => {
function Component() {
return <div />;
}

const ClientComponent = clientExports(Component);

const stream1 = ReactServerDOMServer.renderToReadableStream(
<ClientComponent />,
webpackMap,
);
const response1 =
await ReactServerDOMClient.createFromReadableStream(stream1);

const body = await ReactServerDOMClient.encodeReply(response1);
const serverPayload = await ReactServerDOMServer.decodeReply(body);

const stream2 = ReactServerDOMServer.renderToReadableStream(serverPayload);
const response2 =
await ReactServerDOMClient.createFromReadableStream(stream2);

expect(response2.type).toBe(Component);
});
});

0 comments on commit 1d26103

Please sign in to comment.