From d480782c4162431d06c077ebf8fdf6b8ba7896ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Spie=C3=9F?= Date: Mon, 11 Jun 2018 15:43:30 +0200 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20error=20when=20returning=20an?= =?UTF-8?q?=20empty=20Fragment=20(#12966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Don’t error when returning an empty Fragment When a fragment is reconciled, we directly move onto it’s children. Since an empty `` 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 --- .../src/__tests__/ReactDOMFiber-test.js | 25 +++++++++++++++++++ .../react-reconciler/src/ReactChildFiber.js | 8 +++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiber-test.js b/packages/react-dom/src/__tests__/ReactDOMFiber-test.js index a93dda6ce11e..911f161b0e66 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiber-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiber-test.js @@ -171,6 +171,31 @@ describe('ReactDOMFiber', () => { expect(firstNode.tagName).toBe('DIV'); }); + it('renders an empty fragment', () => { + const Div = () =>
; + const EmptyFragment = () => ; + const NonEmptyFragment = () => ( + +
+ + ); + + ReactDOM.render(, container); + expect(container.firstChild).toBe(null); + + ReactDOM.render(, container); + expect(container.firstChild.tagName).toBe('DIV'); + + ReactDOM.render(, container); + expect(container.firstChild).toBe(null); + + ReactDOM.render(
, container); + expect(container.firstChild.tagName).toBe('DIV'); + + ReactDOM.render(, container); + expect(container.firstChild).toBe(null); + }); + let svgEls, htmlEls, mathEls; const expectSVG = {ref: el => svgEls.push(el)}; const expectHTML = {ref: el => htmlEls.push(el)}; diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index ae19577aa29c..e3d1dd72ed99 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -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.