581
parentObject: Object,
582
key: string,
583
cyclic: boolean,
584
+ response: Response,
585
+ map: (response: Response, model: any) => T,
586
): (value: any) => void {
587
let blocked;
588
if (initializingChunkBlockedModel) {
597
};
598
}
599
return value => {
598
- parentObject[key] = value;
600
+ parentObject[key] = map(response, value);
601
602
// If this is the root object for a model reference, where `blocked.value`
603
// is a stale `null`, the resolved value can be used directly.
604
if (key === '' && blocked.value === null) {
603
- blocked.value = value;
605
+ blocked.value = parentObject[key];
606
}
607
608
blocked.deps--;
653
return proxy;
654
}
655
654
-function getOutlinedModel(response: Response, id: number): any {
656
+function getOutlinedModel<T>(
657
+ response: Response,
658
+ id: number,
659
+ parentObject: Object,
660
+ key: string,
661
+ map: (response: Response, model: any) => T,
662
+): T {
663
const chunk = getChunk(response, id);
664
switch (chunk.status) {
665
case RESOLVED_MODEL:
666
initializeModelChunk(chunk);
667
break;
668
+ case RESOLVED_MODULE:
669
+ initializeModuleChunk(chunk);
670
+ break;
671
}
672
// The status might have changed after initialization.
673
switch (chunk.status) {
663
- case INITIALIZED: {
664
- return chunk.value;
665
- }
666
- // We always encode it first in the stream so it won't be pending.
674
+ case INITIALIZED:
675
+ const chunkValue = map(response, chunk.value);
676
+ if (__DEV__ && chunk._debugInfo) {
677
+ // If we have a direct reference to an object that was rendered by a synchronous
678
+ // server component, it might have some debug info about how it was rendered.
679
+ // We forward this to the underlying object. This might be a React Element or
680
+ // an Array fragment.
681
+ // If this was a string / number return value we lose the debug info. We choose
682
+ // that tradeoff to allow sync server components to return plain values and not
683
+ // use them as React Nodes necessarily. We could otherwise wrap them in a Lazy.
684
+ if (
685
+ typeof chunkValue === 'object' &&
686
+ chunkValue !== null &&
687
+ (Array.isArray(chunkValue) ||
688
+ chunkValue.$$typeof === REACT_ELEMENT_TYPE) &&
689
+ !chunkValue._debugInfo
690
+ ) {
691
+ // We should maybe use a unique symbol for arrays but this is a React owned array.
692
+ // $FlowFixMe[prop-missing]: This should be added to elements.
693
+ Object.defineProperty((chunkValue: any), '_debugInfo', {
694
+ configurable: false,
695
+ enumerable: false,
696
+ writable: true,
697
+ value: chunk._debugInfo,
698
+ });
699
+ }
700
+ }
701
+ return chunkValue;
702
+ case PENDING:
703
+ case BLOCKED:
704
+ case CYCLIC:
705
+ const parentChunk = initializingChunk;
706
+ chunk.then(
707
+ createModelResolver(
708
+ parentChunk,
709
+ parentObject,
710
+ key,
711
+ chunk.status === CYCLIC,
712
+ response,
713
+ map,
714
+ ),
715
+ createModelReject(parentChunk),
716
+ );
717
+ return (null: any);
718
default:
719
throw chunk.reason;
720
}
721
}
722
723
+function createMap(
724
+ response: Response,
725
+ model: Array<[any, any]>,
726
+): Map<any, any> {
727
+ return new Map(model);
728
+}
729
+
730
+function createSet(response: Response, model: Array<any>): Set<any> {
731
+ return new Set(model);
732
+}
733
+
734
+function createBlob(response: Response, model: Array<any>): Blob {
735
+ return new Blob(model.slice(1), {type: model[0]});
736
+}
737
+
738
+function createFormData(
739
+ response: Response,
740
+ model: Array<[any, any]>,
741
+): FormData {
742
+ const formData = new FormData();
743
+ for (let i = 0; i < model.length; i++) {
744
+ formData.append(model[i][0], model[i][1]);
745
+ }
746
+ return formData;
747
+}
748
+
749
+function createModel(response: Response, model: any): any {
750
+ return model;
751
+}
752
+
753
function parseModelString(
754
response: Response,
755
parentObject: Object,
791
case 'F': {
792
// Server Reference
793
const id = parseInt(value.slice(2), 16);
713
- const metadata = getOutlinedModel(response, id);
714
- return createServerReferenceProxy(response, metadata);
794
+ return getOutlinedModel(
795
+ response,
796
+ id,
797
+ parentObject,
798
+ key,
799
+ createServerReferenceProxy,
800
+ );
801
}
802
case 'T': {
803
// Temporary Reference
814
case 'Q': {
815
// Map
816
const id = parseInt(value.slice(2), 16);
731
- const data = getOutlinedModel(response, id);
732
- return new Map(data);
817
+ return getOutlinedModel(response, id, parentObject, key, createMap);
818
}
819
case 'W': {
820
// Set
821
const id = parseInt(value.slice(2), 16);
737
- const data = getOutlinedModel(response, id);
738
- return new Set(data);
822
+ return getOutlinedModel(response, id, parentObject, key, createSet);
823
}
824
case 'B': {
825
// Blob
826
if (enableBinaryFlight) {
827
const id = parseInt(value.slice(2), 16);
744
- const data = getOutlinedModel(response, id);
745
- return new Blob(data.slice(1), {type: data[0]});
828
+ return getOutlinedModel(response, id, parentObject, key, createBlob);
829
}
830
return undefined;
831
}
832
case 'K': {
833
// FormData
834
const id = parseInt(value.slice(2), 16);
752
- const data = getOutlinedModel(response, id);
753
- const formData = new FormData();
754
- for (let i = 0; i < data.length; i++) {
755
- formData.append(data[i][0], data[i][1]);
756
- }
757
- return formData;
835
+ return getOutlinedModel(
836
+ response,
837
+ id,
838
+ parentObject,
839
+ key,
840
+ createFormData,
841
+ );
842
}
843
case 'I': {
844
// $Infinity
887
default: {
888
// We assume that anything else is a reference ID.
889
const id = parseInt(value.slice(1), 16);
806
- const chunk = getChunk(response, id);
807
- switch (chunk.status) {
808
- case RESOLVED_MODEL:
809
- initializeModelChunk(chunk);
810
- break;
811
- case RESOLVED_MODULE:
812
- initializeModuleChunk(chunk);
813
- break;
814
- }
815
- // The status might have changed after initialization.
816
- switch (chunk.status) {
817
- case INITIALIZED:
818
- const chunkValue = chunk.value;
819
- if (__DEV__ && chunk._debugInfo) {
820
- // If we have a direct reference to an object that was rendered by a synchronous
821
- // server component, it might have some debug info about how it was rendered.
822
- // We forward this to the underlying object. This might be a React Element or
823
- // an Array fragment.
824
- // If this was a string / number return value we lose the debug info. We choose
825
- // that tradeoff to allow sync server components to return plain values and not
826
- // use them as React Nodes necessarily. We could otherwise wrap them in a Lazy.
827
- if (
828
- typeof chunkValue === 'object' &&
829
- chunkValue !== null &&
830
- (Array.isArray(chunkValue) ||
831
- chunkValue.$$typeof === REACT_ELEMENT_TYPE) &&
832
- !chunkValue._debugInfo
833
- ) {
834
- // We should maybe use a unique symbol for arrays but this is a React owned array.
835
- // $FlowFixMe[prop-missing]: This should be added to elements.
836
- Object.defineProperty(chunkValue, '_debugInfo', {
837
- configurable: false,
838
- enumerable: false,
839
- writable: true,
840
- value: chunk._debugInfo,
841
- });
842
- }
843
- }
844
- return chunkValue;
845
- case PENDING:
846
- case BLOCKED:
847
- case CYCLIC:
848
- const parentChunk = initializingChunk;
849
- chunk.then(
850
- createModelResolver(
851
- parentChunk,
852
- parentObject,
853
- key,
854
- chunk.status === CYCLIC,
855
- ),
856
- createModelReject(parentChunk),
857
- );
858
- return null;
859
- default:
860
- throw chunk.reason;
861
- }
890
+ return getOutlinedModel(response, id, parentObject, key, createModel);
891
}
892
}
893
}