@@ -15,6 +15,7 @@ import type {
15
15
ReactCustomFormAction ,
16
16
} from 'shared/ReactTypes' ;
17
17
import type { LazyComponent } from 'react/src/ReactLazy' ;
18
+ import type { TemporaryReferenceSet } from './ReactFlightTemporaryReferences' ;
18
19
19
20
import { enableRenderableContext } from 'shared/ReactFeatureFlags' ;
20
21
@@ -32,6 +33,8 @@ import {
32
33
objectName ,
33
34
} from 'shared/ReactSerializationErrors' ;
34
35
36
+ import { writeTemporaryReference } from './ReactFlightTemporaryReferences' ;
37
+
35
38
import isArray from 'shared/isArray' ;
36
39
import getPrototypeOf from 'shared/getPrototypeOf' ;
37
40
@@ -98,6 +101,10 @@ function serializeServerReferenceID(id: number): string {
98
101
return '$F' + id . toString ( 16 ) ;
99
102
}
100
103
104
+ function serializeTemporaryReferenceID(id: number): string {
105
+ return '$T' + id . toString ( 16 ) ;
106
+ }
107
+
101
108
function serializeSymbolReference(name: string): string {
102
109
return '$S' + name ;
103
110
}
@@ -160,6 +167,7 @@ function escapeStringValue(value: string): string {
160
167
export function processReply (
161
168
root : ReactServerValue ,
162
169
formFieldPrefix : string ,
170
+ temporaryReferences : void | TemporaryReferenceSet ,
163
171
resolve : ( string | FormData ) => void ,
164
172
reject : ( error : mixed ) => void ,
165
173
) : void {
@@ -210,9 +218,15 @@ export function processReply(
210
218
if (typeof value === 'object') {
211
219
switch ( ( value : any ) . $$typeof ) {
212
220
case REACT_ELEMENT_TYPE : {
213
- throw new Error (
214
- 'React Element cannot be passed to Server Functions from the Client.' +
215
- ( __DEV__ ? describeObjectForErrorMessage ( parent , key ) : '' ) ,
221
+ if ( temporaryReferences === undefined ) {
222
+ throw new Error (
223
+ 'React Element cannot be passed to Server Functions from the Client without a ' +
224
+ 'temporary reference set. Pass a TemporaryReferenceSet to the options.' +
225
+ ( __DEV__ ? describeObjectForErrorMessage ( parent , key ) : '' ) ,
226
+ ) ;
227
+ }
228
+ return serializeTemporaryReferenceID(
229
+ writeTemporaryReference(temporaryReferences, value),
216
230
);
217
231
}
218
232
case REACT_LAZY_TYPE : {
@@ -366,9 +380,15 @@ export function processReply(
366
380
proto !== ObjectPrototype &&
367
381
( proto === null || getPrototypeOf ( proto ) !== null )
368
382
) {
369
- throw new Error (
370
- 'Only plain objects, and a few built-ins, can be passed to Server Actions. ' +
371
- 'Classes or null prototypes are not supported.' ,
383
+ if ( temporaryReferences === undefined ) {
384
+ throw new Error (
385
+ 'Only plain objects, and a few built-ins, can be passed to Server Actions. ' +
386
+ 'Classes or null prototypes are not supported.' ,
387
+ ) ;
388
+ }
389
+ // We can serialize class instances as temporary references.
390
+ return serializeTemporaryReferenceID(
391
+ writeTemporaryReference(temporaryReferences, value),
372
392
);
373
393
}
374
394
if ( __DEV__ ) {
@@ -450,9 +470,14 @@ export function processReply(
450
470
formData . set ( formFieldPrefix + refId , metaDataJSON ) ;
451
471
return serializeServerReferenceID ( refId ) ;
452
472
}
453
- throw new Error (
454
- 'Client Functions cannot be passed directly to Server Functions. ' +
455
- 'Only Functions passed from the Server can be passed back again.' ,
473
+ if ( temporaryReferences === undefined ) {
474
+ throw new Error (
475
+ 'Client Functions cannot be passed directly to Server Functions. ' +
476
+ 'Only Functions passed from the Server can be passed back again.' ,
477
+ ) ;
478
+ }
479
+ return serializeTemporaryReferenceID (
480
+ writeTemporaryReference ( temporaryReferences , value ) ,
456
481
) ;
457
482
}
458
483
@@ -511,6 +536,7 @@ function encodeFormData(reference: any): Thenable<FormData> {
511
536
processReply (
512
537
reference ,
513
538
'' ,
539
+ undefined , // TODO: This means React Elements can't be used as state in progressive enhancement.
514
540
( body : string | FormData ) => {
515
541
if ( typeof body === 'string' ) {
516
542
const data = new FormData ( ) ;
0 commit comments