@@ -865,20 +865,95 @@ function renderFunctionComponent<Props>(
865
865
} else {
866
866
result = Component ( props , secondArg ) ;
867
867
}
868
- if (
869
- typeof result === 'object' &&
870
- result !== null &&
871
- typeof result . then === 'function '
872
- ) {
873
- // When the return value is in children position we can resolve it immediately,
874
- // to its value without a wrapper if it's synchronously available.
875
- const thenable : Thenable < any > = result ;
876
- if ( thenable . status === 'fulfilled' ) {
877
- return thenable . value ;
878
- }
879
- // TODO: Once we accept Promises as children on the client, we can just return
880
- // the thenable here.
881
- result = createLazyWrapperAroundWakeable ( result ) ;
868
+ if (typeof result === 'object' && result !== null ) {
869
+ if ( typeof result . then === 'function' ) {
870
+ // When the return value is in children position we can resolve it immediately,
871
+ // to its value without a wrapper if it's synchronously available.
872
+ const thenable : Thenable < any > = result ;
873
+ if ( thenable . status === 'fulfilled' ) {
874
+ return thenable . value ;
875
+ }
876
+ // TODO: Once we accept Promises as children on the client, we can just return
877
+ // the thenable here.
878
+ result = createLazyWrapperAroundWakeable ( result ) ;
879
+ }
880
+
881
+ // Normally we'd serialize an Iterator/AsyncIterator as a single-shot which is not compatible
882
+ // to be rendered as a React Child. However, because we have the function to recreate
883
+ // an iterable from rendering the element again, we can effectively treat it as multi-
884
+ // shot. Therefore we treat this as an Iterable/AsyncIterable, whether it was one or not, by
885
+ // adding a wrapper so that this component effectively renders down to an AsyncIterable.
886
+ const iteratorFn = getIteratorFn(result);
887
+ if (iteratorFn) {
888
+ const iterableChild = result ;
889
+ result = {
890
+ [ Symbol . iterator ] : function ( ) {
891
+ const iterator = iteratorFn . call ( iterableChild ) ;
892
+ if ( __DEV__ ) {
893
+ // If this was an Iterator but not a GeneratorFunction we warn because
894
+ // it might have been a mistake. Technically you can make this mistake with
895
+ // GeneratorFunctions and even single-shot Iterables too but it's extra
896
+ // tempting to try to return the value from a generator.
897
+ if ( iterator === iterableChild ) {
898
+ const isGeneratorComponent =
899
+ // $FlowIgnore[method-unbinding]
900
+ Object . prototype . toString . call ( Component ) ===
901
+ '[object GeneratorFunction]' &&
902
+ // $FlowIgnore[method-unbinding]
903
+ Object . prototype . toString . call ( iterableChild ) ===
904
+ '[object Generator]' ;
905
+ if ( ! isGeneratorComponent ) {
906
+ console . error (
907
+ 'Returning an Iterator from a Server Component is not supported ' +
908
+ 'since it cannot be looped over more than once. ' ,
909
+ ) ;
910
+ }
911
+ }
912
+ }
913
+ return ( iterator : any ) ;
914
+ } ,
915
+ } ;
916
+ if ( __DEV__ ) {
917
+ ( result : any ) . _debugInfo = iterableChild . _debugInfo ;
918
+ }
919
+ } else if (
920
+ enableFlightReadableStream &&
921
+ typeof ( result : any ) [ ASYNC_ITERATOR ] === 'function ' &&
922
+ ( typeof ReadableStream !== 'function ' ||
923
+ ! ( result instanceof ReadableStream ) )
924
+ ) {
925
+ const iterableChild = result ;
926
+ result = {
927
+ [ ASYNC_ITERATOR ] : function ( ) {
928
+ const iterator = ( iterableChild : any ) [ ASYNC_ITERATOR ] ( ) ;
929
+ if ( __DEV__ ) {
930
+ // If this was an AsyncIterator but not an AsyncGeneratorFunction we warn because
931
+ // it might have been a mistake. Technically you can make this mistake with
932
+ // AsyncGeneratorFunctions and even single-shot AsyncIterables too but it's extra
933
+ // tempting to try to return the value from a generator.
934
+ if ( iterator === iterableChild ) {
935
+ const isGeneratorComponent =
936
+ // $FlowIgnore[method-unbinding]
937
+ Object . prototype . toString . call ( Component ) ===
938
+ '[object AsyncGeneratorFunction]' &&
939
+ // $FlowIgnore[method-unbinding]
940
+ Object . prototype . toString . call ( iterableChild ) ===
941
+ '[object AsyncGenerator]' ;
942
+ if ( ! isGeneratorComponent ) {
943
+ console . error (
944
+ 'Returning an AsyncIterator from a Server Component is not supported ' +
945
+ 'since it cannot be looped over more than once. ' ,
946
+ ) ;
947
+ }
948
+ }
949
+ }
950
+ return iterator ;
951
+ } ,
952
+ } ;
953
+ if ( __DEV__ ) {
954
+ ( result : any ) . _debugInfo = iterableChild . _debugInfo ;
955
+ }
956
+ }
882
957
}
883
958
// Track this element's key on the Server Component on the keyPath context..
884
959
const prevKeyPath = task . keyPath ;
0 commit comments