mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Don’t error when returning an empty Fragment (#12966)
* Don’t error when returning an empty Fragment When a fragment is reconciled, we directly move onto it’s children. Since an empty `<React.Fragment/>` will have children of `undefined`, this would always throw. To fix this, we bail out in those cases. * Test the update path as well * Reuse existing code path * An even more explicit solution that also fixes Flow
This commit is contained in:
committed by
Dan Abramov
parent
4ac6f133af
commit
d480782c41
@@ -171,6 +171,31 @@ describe('ReactDOMFiber', () => {
|
||||
expect(firstNode.tagName).toBe('DIV');
|
||||
});
|
||||
|
||||
it('renders an empty fragment', () => {
|
||||
const Div = () => <div />;
|
||||
const EmptyFragment = () => <React.Fragment />;
|
||||
const NonEmptyFragment = () => (
|
||||
<React.Fragment>
|
||||
<Div />
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
ReactDOM.render(<EmptyFragment />, container);
|
||||
expect(container.firstChild).toBe(null);
|
||||
|
||||
ReactDOM.render(<NonEmptyFragment />, container);
|
||||
expect(container.firstChild.tagName).toBe('DIV');
|
||||
|
||||
ReactDOM.render(<EmptyFragment />, container);
|
||||
expect(container.firstChild).toBe(null);
|
||||
|
||||
ReactDOM.render(<Div />, container);
|
||||
expect(container.firstChild.tagName).toBe('DIV');
|
||||
|
||||
ReactDOM.render(<EmptyFragment />, container);
|
||||
expect(container.firstChild).toBe(null);
|
||||
});
|
||||
|
||||
let svgEls, htmlEls, mathEls;
|
||||
const expectSVG = {ref: el => svgEls.push(el)};
|
||||
const expectHTML = {ref: el => htmlEls.push(el)};
|
||||
|
||||
+4
-4
@@ -1208,12 +1208,12 @@ function ChildReconciler(shouldTrackSideEffects) {
|
||||
// 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.
|
||||
if (
|
||||
const isUnkeyedTopLevelFragment =
|
||||
typeof newChild === 'object' &&
|
||||
newChild !== null &&
|
||||
newChild.type === REACT_FRAGMENT_TYPE &&
|
||||
newChild.key === null
|
||||
) {
|
||||
newChild.key === null;
|
||||
if (isUnkeyedTopLevelFragment) {
|
||||
newChild = newChild.props.children;
|
||||
}
|
||||
|
||||
@@ -1281,7 +1281,7 @@ function ChildReconciler(shouldTrackSideEffects) {
|
||||
warnOnFunctionType();
|
||||
}
|
||||
}
|
||||
if (typeof newChild === 'undefined') {
|
||||
if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) {
|
||||
// If the new child is undefined, and the return fiber is a composite
|
||||
// component, throw an error. If Fiber return types are disabled,
|
||||
// we already threw above.
|
||||
|
||||
Reference in New Issue
Block a user