Skip to content

Commit 7dabec5

Browse files
committed
Test top level fragment inside lazy semantics
1 parent 7909d8e commit 7dabec5

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

packages/react-reconciler/src/ReactChildFiber.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,15 +1460,18 @@ function createChildReconciler(
14601460
lanes: Lanes,
14611461
debugInfo: ReactDebugInfo | null,
14621462
): Fiber | null {
1463-
// This function is not recursive.
1463+
// This function is only recursive for Usables/Lazy and not nested arrays.
1464+
// That's so that using a Lazy wrapper is unobservable to the Fragment
1465+
// convention.
14641466
// If the top level item is an array, we treat it as a set of children,
14651467
// not as a fragment. Nested arrays on the other hand will be treated as
14661468
// fragment nodes. Recursion happens at the normal flow.
14671469

14681470
// Handle top level unkeyed fragments as if they were arrays.
14691471
// This leads to an ambiguity between <>{[...]}</> and <>...</>.
14701472
// We treat the ambiguous cases above the same.
1471-
// TODO: Let's use recursion like we do for Usable nodes?
1473+
// We don't use recursion here because a fragment inside a fragment
1474+
// is no longer considered "top level" for these purposes.
14721475
const isUnkeyedTopLevelFragment =
14731476
typeof newChild === 'object' &&
14741477
newChild !== null &&

packages/react-reconciler/src/__tests__/ReactFragment-test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,4 +965,51 @@ describe('ReactFragment', () => {
965965
</>,
966966
);
967967
});
968+
969+
it('should preserve state of children when adding a fragment wrapped in Lazy', async function () {
970+
const ops = [];
971+
972+
class Stateful extends React.Component {
973+
componentDidUpdate() {
974+
ops.push('Update Stateful');
975+
}
976+
977+
render() {
978+
return <div>Hello</div>;
979+
}
980+
}
981+
982+
const lazyChild = React.lazy(async () => ({
983+
default: (
984+
<>
985+
<Stateful key="a" />
986+
<div key="b">World</div>
987+
</>
988+
),
989+
}));
990+
991+
function Foo({condition}) {
992+
return condition ? <Stateful key="a" /> : lazyChild;
993+
}
994+
995+
ReactNoop.render(<Foo condition={true} />);
996+
await waitForAll([]);
997+
998+
ReactNoop.render(<Foo condition={false} />);
999+
await waitForAll([]);
1000+
1001+
expect(ops).toEqual(['Update Stateful']);
1002+
expect(ReactNoop).toMatchRenderedOutput(
1003+
<>
1004+
<div>Hello</div>
1005+
<div>World</div>
1006+
</>,
1007+
);
1008+
1009+
ReactNoop.render(<Foo condition={true} />);
1010+
await waitForAll([]);
1011+
1012+
expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
1013+
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
1014+
});
9681015
});

0 commit comments

Comments
 (0)