0
# Data Communication
1
2
Functions for encoding client-to-server data, decoding server responses, and handling form actions in React Server Components applications.
3
4
## Capabilities
5
6
### Encode Reply
7
8
Encodes client-side data for transmission to the server, supporting complex data structures, files, and temporary references.
9
10
```javascript { .api }
11
/**
12
* Encodes client data for server transmission
13
* @param value - Any serializable value to encode
14
* @param options - Optional encoding configuration
15
* @returns Promise resolving to encoded data in appropriate format
16
*/
17
function encodeReply(
18
value: ReactServerValue,
19
options?: EncodeReplyOptions
20
): Promise<string | URLSearchParams | FormData>;
21
```
22
23
**Usage Examples:**
24
25
```javascript
26
import { encodeReply } from "react-server-dom-webpack/client.browser";
27
28
// Encode simple data
29
const simpleData = await encodeReply({
30
action: "updateProfile",
31
userId: 123,
32
name: "John Doe"
33
});
34
35
// Encode with files
36
const formData = await encodeReply({
37
message: "Hello server",
38
files: [fileInput.files[0], fileInput.files[1]],
39
metadata: { timestamp: Date.now() }
40
});
41
42
// Encode with abort signal
43
const abortController = new AbortController();
44
const encodedData = await encodeReply(complexObject, {
45
signal: abortController.signal
46
});
47
48
// Send to server
49
await fetch("/api/server-action", {
50
method: "POST",
51
body: encodedData
52
});
53
```
54
55
### Decode Reply
56
57
Decodes client-transmitted data on the server side, handling various formats including FormData and JSON strings.
58
59
```javascript { .api }
60
/**
61
* Decodes client data sent to the server
62
* @param body - Request body containing encoded client data
63
* @param webpackMap - Optional server manifest for module resolution
64
* @param options - Optional configuration with temporary references
65
* @returns Promise resolving to decoded client data
66
*/
67
function decodeReply<T>(
68
body: string | FormData,
69
webpackMap?: ServerManifest,
70
options?: {temporaryReferences?: TemporaryReferenceSet}
71
): Thenable<T>;
72
```
73
74
**Usage Examples:**
75
76
```javascript
77
import { decodeReply } from "react-server-dom-webpack/server.node";
78
79
// Handle POST request with encoded data
80
export async function POST(request) {
81
const serverManifest = await loadServerManifest();
82
83
// Decode string body
84
const stringData = decodeReply(
85
await request.text(),
86
serverManifest
87
);
88
89
// Or decode FormData body
90
const formData = decodeReply(
91
await request.formData(),
92
serverManifest
93
);
94
95
// Process decoded data
96
const result = await processAction(formData);
97
return Response.json(result);
98
}
99
100
// Handle multipart uploads
101
async function handleUpload(request) {
102
const formData = await request.formData();
103
const decodedData = decodeReply(formData, serverManifest);
104
105
// Access files and regular data
106
const { files, userInput, metadata } = decodedData;
107
108
return processUpload(files, userInput, metadata);
109
}
110
```
111
112
### Decode Reply from Busboy
113
114
Specialized decoding for multipart form data using the busboy library, ideal for file uploads in Node.js environments.
115
116
```javascript { .api }
117
/**
118
* Decodes multipart form data using busboy for Node.js
119
* @param busboyStream - Busboy stream processing multipart data
120
* @param bundlerConfig - Optional server manifest for module resolution
121
* @returns Promise resolving to decoded form data with files and fields
122
*/
123
function decodeReplyFromBusboy(
124
busboyStream: any,
125
bundlerConfig?: ServerManifest
126
): Promise<any>;
127
```
128
129
**Usage Examples:**
130
131
```javascript
132
import { decodeReplyFromBusboy } from "react-server-dom-webpack/server.node";
133
import busboy from "busboy";
134
import { IncomingMessage } from "http";
135
136
// Handle file upload with busboy
137
async function handleFileUpload(req: IncomingMessage) {
138
const bb = busboy({
139
headers: req.headers,
140
limits: { fileSize: 10 * 1024 * 1024 } // 10MB limit
141
});
142
143
const decodedData = await decodeReplyFromBusboy(bb, serverManifest);
144
145
// Process uploaded files and form fields
146
const { files, fields } = decodedData;
147
148
for (const file of files) {
149
console.log(`Uploaded: ${file.filename}, Size: ${file.size}`);
150
await saveFile(file);
151
}
152
153
return { success: true, uploadedFiles: files.length };
154
}
155
156
// Express.js integration
157
app.post("/upload", async (req, res) => {
158
try {
159
const result = await handleFileUpload(req);
160
res.json(result);
161
} catch (error) {
162
res.status(500).json({ error: error.message });
163
}
164
});
165
```
166
167
### Decode Action
168
169
Decodes form actions submitted from client components, returning executable server functions.
170
171
```javascript { .api }
172
/**
173
* Decodes form action from client form submission
174
* @param body - FormData containing action information and arguments
175
* @param bundlerConfig - Optional server manifest for action resolution
176
* @returns Promise resolving to executable action function or null
177
*/
178
function decodeAction(
179
body: FormData,
180
bundlerConfig?: ServerManifest
181
): Promise<() => any> | null;
182
```
183
184
**Usage Examples:**
185
186
```javascript
187
import { decodeAction } from "react-server-dom-webpack/server.browser";
188
189
// Handle form action submission
190
export async function POST(request) {
191
const formData = await request.formData();
192
const action = await decodeAction(formData, serverManifest);
193
194
if (!action) {
195
return new Response("Invalid action", { status: 400 });
196
}
197
198
try {
199
// Execute the decoded action
200
const result = await action();
201
return Response.json(result);
202
} catch (error) {
203
return new Response(error.message, { status: 500 });
204
}
205
}
206
207
// Progressive enhancement form handling
208
async function handleFormSubmission(request) {
209
const formData = await request.formData();
210
211
// Try to decode as action first
212
const action = await decodeAction(formData, serverManifest);
213
214
if (action) {
215
// Handle as server action
216
return await action();
217
} else {
218
// Handle as traditional form submission
219
return handleTraditionalForm(formData);
220
}
221
}
222
```
223
224
### Decode Form State
225
226
Decodes form state information for progressive enhancement and form validation scenarios.
227
228
```javascript { .api }
229
/**
230
* Decodes form state from action result and form data
231
* @param actionResult - Result from previous action execution
232
* @param body - FormData containing current form state
233
* @param bundlerConfig - Optional server manifest for state resolution
234
* @returns Decoded form state for progressive enhancement
235
*/
236
function decodeFormState(
237
actionResult: any,
238
body: FormData,
239
bundlerConfig?: ServerManifest
240
): any;
241
```
242
243
**Usage Examples:**
244
245
```javascript
246
import { decodeFormState } from "react-server-dom-webpack/server.browser";
247
248
// Handle form with validation state
249
export async function handleFormWithState(request, previousResult) {
250
const formData = await request.formData();
251
252
const formState = decodeFormState(
253
previousResult,
254
formData,
255
serverManifest
256
);
257
258
// Use form state for validation and user feedback
259
if (formState.errors) {
260
return renderFormWithErrors(formState);
261
}
262
263
// Process valid form
264
return processValidForm(formState.data);
265
}
266
267
// Multi-step form handling
268
async function handleMultiStepForm(request, stepResult) {
269
const formData = await request.formData();
270
const currentState = decodeFormState(stepResult, formData, serverManifest);
271
272
if (currentState.isComplete) {
273
return processCompleteForm(currentState);
274
} else {
275
return renderNextStep(currentState);
276
}
277
}
278
```
279
280
### Data Serialization Patterns
281
282
Common patterns for handling complex data structures in client-server communication.
283
284
**Complex Object Encoding:**
285
286
```javascript
287
// Client-side: Encode complex nested object
288
const complexData = {
289
user: { id: 1, name: "Alice" },
290
preferences: { theme: "dark", notifications: true },
291
files: [file1, file2],
292
metadata: {
293
timestamp: new Date(),
294
location: navigator.geolocation
295
}
296
};
297
298
const encoded = await encodeReply(complexData);
299
300
// Server-side: Decode and access nested data
301
const decoded = decodeReply(await request.formData(), serverManifest);
302
console.log(decoded.user.name); // "Alice"
303
console.log(decoded.files.length); // 2
304
```
305
306
**File Upload Handling:**
307
308
```javascript
309
// Client-side: Encode files with metadata
310
const fileData = {
311
action: "uploadDocument",
312
files: Array.from(fileInput.files),
313
category: "documents",
314
tags: ["important", "project-a"]
315
};
316
317
const formData = await encodeReply(fileData);
318
319
// Server-side: Process uploaded files
320
const { action, files, category, tags } = decodeReply(formData, serverManifest);
321
322
for (const file of files) {
323
await saveFileWithMetadata(file, { category, tags });
324
}
325
```
326
327
## Types
328
329
```javascript { .api }
330
interface EncodeReplyOptions {
331
/** Set for tracking temporary references during encoding */
332
temporaryReferences?: TemporaryReferenceSet;
333
/** AbortSignal for cancelling encoding operation */
334
signal?: AbortSignal;
335
}
336
337
type ReactServerValue =
338
| string
339
| number
340
| boolean
341
| null
342
| undefined
343
| Array<ReactServerValue>
344
| { [key: string]: ReactServerValue }
345
| File
346
| Blob
347
| FormData
348
| URLSearchParams;
349
350
type ServerManifest = Record<string, any>;
351
type TemporaryReferenceSet = any;
352
353
interface DecodedFormData {
354
/** Uploaded files from multipart form */
355
files?: File[];
356
/** Form field values */
357
fields?: Record<string, string | string[]>;
358
/** Any additional encoded data */
359
[key: string]: any;
360
}
361
```