Skip to content

Commit

Permalink
Support FormData from Server to Client
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Apr 5, 2024
1 parent fd0da3e commit eee6951
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
10 changes: 10 additions & 0 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,16 @@ function parseModelString(
const data = getOutlinedModel(response, id);
return new Set(data);
}
case 'K': {
// FormData
const id = parseInt(value.slice(2), 16);
const data = getOutlinedModel(response, id);
const formData = new FormData();
for (let i = 0; i < data.length; i++) {
formData.append(data[i][0], data[i][1]);
}
return formData;
}
case 'I': {
// $Infinity
return Infinity;
Expand Down
34 changes: 34 additions & 0 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,40 @@ describe('ReactFlight', () => {
`);
});

if (typeof FormData !== 'undefined') {
it('can transport FormData (no blobs)', async () => {
function ComponentClient({prop}) {
return `
formData: ${prop instanceof FormData}
hi: ${prop.get('hi')}
multiple: ${prop.getAll('multiple')}
content: ${JSON.stringify(Array.from(prop))}
`;
}
const Component = clientReference(ComponentClient);

const formData = new FormData();
formData.append('hi', 'world');
formData.append('multiple', 1);
formData.append('multiple', 2);

const model = <Component prop={formData} />;

const transport = ReactNoopFlightServer.render(model);

await act(async () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});

expect(ReactNoop).toMatchRenderedOutput(`
formData: true
hi: world
multiple: 1,2
content: [["hi","world"],["multiple","1"],["multiple","2"]]
`);
});
}

it('can transport cyclic objects', async () => {
function ComponentClient({prop}) {
expect(prop.obj.obj.obj).toBe(prop.obj.obj);
Expand Down
14 changes: 14 additions & 0 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,12 @@ function serializeMap(
return '$Q' + id.toString(16);
}

function serializeFormData(request: Request, formData: FormData): string {
const entries = Array.from(formData.entries());
const id = outlineModel(request, (entries: any));
return '$K' + id.toString(16);
}

function serializeSet(request: Request, set: Set<ReactClientValue>): string {
const entries = Array.from(set);
for (let i = 0; i < entries.length; i++) {
Expand Down Expand Up @@ -1506,6 +1512,10 @@ function renderModelDestructive(
if (value instanceof Set) {
return serializeSet(request, value);
}
// TODO: FormData is not available in old Node. Remove the typeof later.
if (typeof FormData === 'function' && value instanceof FormData) {
return serializeFormData(request, value);
}

if (enableBinaryFlight) {
if (value instanceof ArrayBuffer) {
Expand Down Expand Up @@ -2027,6 +2037,10 @@ function renderConsoleValue(
if (value instanceof Set) {
return serializeSet(request, value);
}
// TODO: FormData is not available in old Node. Remove the typeof later.
if (typeof FormData === 'function' && value instanceof FormData) {
return serializeFormData(request, value);
}

if (enableBinaryFlight) {
if (value instanceof ArrayBuffer) {
Expand Down

0 comments on commit eee6951

Please sign in to comment.