@@ -478,6 +478,58 @@ function createLazyWrapperAroundWakeable(wakeable: Wakeable) {
478
478
return lazyType ;
479
479
}
480
480
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
+
481
533
function renderFragment (
482
534
request : Request ,
483
535
task : Task ,
@@ -581,48 +633,7 @@ function renderElement(
581
633
return renderClientElement ( task , type , key , props ) ;
582
634
}
583
635
// 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);
626
637
} else if ( typeof type === 'string ') {
627
638
// This is a host element. E.g. HTML.
628
639
return renderClientElement ( task , type , key , props ) ;
@@ -660,39 +671,7 @@ function renderElement(
660
671
return renderElement ( request , task , wrappedType , key , ref , props ) ;
661
672
}
662
673
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 ) ;
696
675
}
697
676
case REACT_MEMO_TYPE: {
698
677
return renderElement ( request , task , type . type , key , ref , props ) ;
0 commit comments