@@ -478,6 +478,58 @@ function createLazyWrapperAroundWakeable(wakeable: Wakeable) {
478478 return lazyType ;
479479}
480480
481+ function renderFunctionComponent< Props > (
482+ request: Request,
483+ task: Task,
484+ key: null | string,
485+ Component: (p: Props, arg: void) => any ,
486+ props : Props ,
487+ ) : ReactJSONValue {
488+ // Reset the task's thenable state before continuing, so that if a later
489+ // component suspends we can reuse the same task object. If the same
490+ // component suspends again, the thenable state will be restored.
491+ const prevThenableState = task . thenableState ;
492+ task . thenableState = null ;
493+
494+ prepareToUseHooksForComponent ( prevThenableState ) ;
495+ // The secondArg is always undefined in Server Components since refs error early.
496+ const secondArg = undefined ;
497+ let result = Component ( props , secondArg ) ;
498+ if (
499+ typeof result === 'object' &&
500+ result !== null &&
501+ typeof result . then === 'function'
502+ ) {
503+ // When the return value is in children position we can resolve it immediately,
504+ // to its value without a wrapper if it's synchronously available.
505+ const thenable : Thenable < any > = result ;
506+ if ( thenable . status === 'fulfilled' ) {
507+ return thenable . value ;
508+ }
509+ // TODO: Once we accept Promises as children on the client, we can just return
510+ // the thenable here.
511+ result = createLazyWrapperAroundWakeable ( result ) ;
512+ }
513+ // Track this element's key on the Server Component on the keyPath context..
514+ const prevKeyPath = task . keyPath ;
515+ const prevImplicitSlot = task . implicitSlot ;
516+ if ( key !== null ) {
517+ // Append the key to the path. Technically a null key should really add the child
518+ // index. We don't do that to hold the payload small and implementation simple.
519+ task . keyPath = prevKeyPath === null ? key : prevKeyPath + ',' + key ;
520+ } else if (prevKeyPath === null) {
521+ // This sequence of Server Components has no keys. This means that it was rendered
522+ // in a slot that needs to assign an implicit key. Even if children below have
523+ // explicit keys, they should not be used for the outer most key since it might
524+ // collide with other slots in that set.
525+ task . implicitSlot = true ;
526+ }
527+ const json = renderModelDestructive(request, task, emptyRoot, '', result);
528+ task.keyPath = prevKeyPath;
529+ task.implicitSlot = prevImplicitSlot;
530+ return json;
531+ }
532+
481533function renderFragment (
482534 request : Request ,
483535 task : Task ,
@@ -581,48 +633,7 @@ function renderElement(
581633 return renderClientElement ( task , type , key , props ) ;
582634 }
583635 // This is a server-side component.
584-
585- // Reset the task's thenable state before continuing, so that if a later
586- // component suspends we can reuse the same task object. If the same
587- // component suspends again, the thenable state will be restored.
588- const prevThenableState = task.thenableState;
589- task.thenableState = null;
590-
591- prepareToUseHooksForComponent(prevThenableState);
592- let result = type(props);
593- if (
594- typeof result === 'object' &&
595- result !== null &&
596- typeof result . then === 'function '
597- ) {
598- // When the return value is in children position we can resolve it immediately,
599- // to its value without a wrapper if it's synchronously available.
600- const thenable : Thenable < any > = result ;
601- if ( thenable . status === 'fulfilled' ) {
602- return thenable . value ;
603- }
604- // TODO: Once we accept Promises as children on the client, we can just return
605- // the thenable here.
606- result = createLazyWrapperAroundWakeable ( result ) ;
607- }
608- // Track this element's key on the Server Component on the keyPath context..
609- const prevKeyPath = task.keyPath;
610- const prevImplicitSlot = task.implicitSlot;
611- if (key !== null) {
612- // Append the key to the path. Technically a null key should really add the child
613- // index. We don't do that to hold the payload small and implementation simple.
614- task . keyPath = prevKeyPath === null ? key : prevKeyPath + ',' + key ;
615- } else if (prevKeyPath === null) {
616- // This sequence of Server Components has no keys. This means that it was rendered
617- // in a slot that needs to assign an implicit key. Even if children below have
618- // explicit keys, they should not be used for the outer most key since it might
619- // collide with other slots in that set.
620- task . implicitSlot = true ;
621- }
622- const json = renderModelDestructive(request, task, emptyRoot, '', result);
623- task.keyPath = prevKeyPath;
624- task.implicitSlot = prevImplicitSlot;
625- return json;
636+ return renderFunctionComponent(request, task, key, type, props);
626637 } else if ( typeof type === 'string ') {
627638 // This is a host element. E.g. HTML.
628639 return renderClientElement ( task , type , key , props ) ;
@@ -660,39 +671,7 @@ function renderElement(
660671 return renderElement ( request , task , wrappedType , key , ref , props ) ;
661672 }
662673 case REACT_FORWARD_REF_TYPE: {
663- const render = type . render ;
664-
665- // Reset the task's thenable state before continuing, so that if a later
666- // component suspends we can reuse the same task object. If the same
667- // component suspends again, the thenable state will be restored.
668- const prevThenableState = task . thenableState ;
669- task . thenableState = null ;
670-
671- prepareToUseHooksForComponent ( prevThenableState ) ;
672- const result = render ( props , undefined ) ;
673- const prevKeyPath = task . keyPath ;
674- const prevImplicitSlot = task . implicitSlot ;
675- if ( key !== null ) {
676- // Append the key to the path. Technically a null key should really add the child
677- // index. We don't do that to hold the payload small and implementation simple.
678- task. keyPath = prevKeyPath === null ? key : prevKeyPath + ',' + key ;
679- } else if (prevKeyPath === null) {
680- // This sequence of Server Components has no keys. This means that it was rendered
681- // in a slot that needs to assign an implicit key. Even if children below have
682- // explicit keys, they should not be used for the outer most key since it might
683- // collide with other slots in that set.
684- task . implicitSlot = true ;
685- }
686- const json = renderModelDestructive(
687- request,
688- task,
689- emptyRoot,
690- '',
691- result,
692- );
693- task.keyPath = prevKeyPath;
694- task.implicitSlot = prevImplicitSlot;
695- return json;
674+ return renderFunctionComponent ( request , task , key , type . render , props ) ;
696675 }
697676 case REACT_MEMO_TYPE: {
698677 return renderElement ( request , task , type . type , key , ref , props ) ;
0 commit comments