Skip to content

Commit

Permalink
Test top level fragment inside lazy semantics
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Apr 17, 2024
1 parent 7909d8e commit 7dabec5
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
7 changes: 5 additions & 2 deletions packages/react-reconciler/src/ReactChildFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -1460,15 +1460,18 @@ function createChildReconciler(
lanes: Lanes,
debugInfo: ReactDebugInfo | null,
): Fiber | null {
// This function is not recursive.
// This function is only recursive for Usables/Lazy and not nested arrays.
// That's so that using a Lazy wrapper is unobservable to the Fragment
// convention.
// If the top level item is an array, we treat it as a set of children,
// not as a fragment. Nested arrays on the other hand will be treated as
// fragment nodes. Recursion happens at the normal flow.

// Handle top level unkeyed fragments as if they were arrays.
// This leads to an ambiguity between <>{[...]}</> and <>...</>.
// We treat the ambiguous cases above the same.
// TODO: Let's use recursion like we do for Usable nodes?
// We don't use recursion here because a fragment inside a fragment
// is no longer considered "top level" for these purposes.
const isUnkeyedTopLevelFragment =
typeof newChild === 'object' &&
newChild !== null &&
Expand Down
47 changes: 47 additions & 0 deletions packages/react-reconciler/src/__tests__/ReactFragment-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -965,4 +965,51 @@ describe('ReactFragment', () => {
</>,
);
});

it('should preserve state of children when adding a fragment wrapped in Lazy', async function () {
const ops = [];

class Stateful extends React.Component {
componentDidUpdate() {
ops.push('Update Stateful');
}

render() {
return <div>Hello</div>;
}
}

const lazyChild = React.lazy(async () => ({
default: (
<>
<Stateful key="a" />
<div key="b">World</div>
</>
),
}));

function Foo({condition}) {
return condition ? <Stateful key="a" /> : lazyChild;
}

ReactNoop.render(<Foo condition={true} />);
await waitForAll([]);

ReactNoop.render(<Foo condition={false} />);
await waitForAll([]);

expect(ops).toEqual(['Update Stateful']);
expect(ReactNoop).toMatchRenderedOutput(
<>
<div>Hello</div>
<div>World</div>
</>,
);

ReactNoop.render(<Foo condition={true} />);
await waitForAll([]);

expect(ops).toEqual(['Update Stateful', 'Update Stateful']);
expect(ReactNoop).toMatchRenderedOutput(<div>Hello</div>);
});
});

0 comments on commit 7dabec5

Please sign in to comment.