@@ -516,6 +516,48 @@ function createLazyWrapperAroundWakeable(wakeable: Wakeable) {
516
516
return lazyType ;
517
517
}
518
518
519
+ function renderFragment(
520
+ request: Request,
521
+ task: Task,
522
+ children: $ReadOnlyArray< ReactClientValue > ,
523
+ ): ReactJSONValue {
524
+ if ( ! enableServerComponentKeys ) {
525
+ return children ;
526
+ }
527
+ if (task.keyPath !== null) {
528
+ // We have a Server Component that specifies a key but we're now splitting
529
+ // the tree using a fragment.
530
+ const fragment = [
531
+ REACT_ELEMENT_TYPE ,
532
+ REACT_FRAGMENT_TYPE ,
533
+ task . keyPath ,
534
+ { children} ,
535
+ ] ;
536
+ if ( ! task . implicitSlot ) {
537
+ // If this was keyed inside a set. I.e. the outer Server Component was keyed
538
+ // then we need to handle reorders of the whole set. To do this we need to wrap
539
+ // this array in a keyed Fragment.
540
+ return fragment ;
541
+ }
542
+ // If the outer Server Component was implicit but then an inner one had a key
543
+ // we don't actually need to be able to move the whole set around. It'll always be
544
+ // in an implicit slot. The key only exists to be able to reset the state of the
545
+ // children. We could achieve the same effect by passing on the keyPath to the next
546
+ // set of components inside the fragment. This would also allow a keyless fragment
547
+ // reconcile against a single child.
548
+ // Unfortunately because of JSON.stringify, we can't call the recursive loop for
549
+ // each child within this context because we can't return a set with already resolved
550
+ // values. E.g. a string would get double encoded. Returning would pop the context.
551
+ // So instead, we wrap it with an unkeyed fragment and inner keyed fragment.
552
+ return [ fragment ] ;
553
+ }
554
+ // Since we're yielding here, that implicitly resets the keyPath context on the
555
+ // way up. Which is what we want since we've consumed it. If this changes to
556
+ // be recursive serialization, we need to reset the keyPath and implicitSlot,
557
+ // before recursing here.
558
+ return children;
559
+ }
560
+
519
561
function renderClientElement (
520
562
task : Task ,
521
563
type : any ,
@@ -638,6 +680,7 @@ function renderElement(
638
680
props.children,
639
681
);
640
682
task.implicitSlot = prevImplicitSlot;
683
+ return json;
641
684
}
642
685
// This might be a built-in React component. We'll let the client decide.
643
686
// Any built-in works as long as its props are serializable.
@@ -1334,8 +1377,7 @@ function renderModelDestructive(
1334
1377
}
1335
1378
1336
1379
if (isArray(value)) {
1337
- // $FlowFixMe[incompatible-return]
1338
- return value ;
1380
+ return renderFragment ( request , task , value ) ;
1339
1381
}
1340
1382
1341
1383
if (value instanceof Map) {
@@ -1401,7 +1443,7 @@ function renderModelDestructive(
1401
1443
1402
1444
const iteratorFn = getIteratorFn ( value ) ;
1403
1445
if ( iteratorFn ) {
1404
- return Array . from ( ( value : any ) ) ;
1446
+ return renderFragment ( request , task , Array . from ( ( value : any ) ) ) ;
1405
1447
}
1406
1448
1407
1449
// Verify that this is a simple plain object.
0 commit comments