478
return lazyType;
479
}
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
+
533
function renderFragment(
534
request: Request,
535
task: Task,
633
return renderClientElement(task, type, key, props);
634
}
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);
637
} else if (typeof type === 'string') {
638
// This is a host element. E.g. HTML.
639
return renderClientElement(task, type, key, props);
671
return renderElement(request, task, wrappedType, key, ref, props);
672
}
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);
675
}
676
case REACT_MEMO_TYPE: {
677
return renderElement(request, task, type.type, key, ref, props);