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