@samitouri / QOS-React / commits / d480782c41

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

Philipp Spieß committed Jun 11, 2018 at 15:43 UTC d480782c4162431d06c077ebf8fdf6b8ba7896ef
2 files changed +29 -4
packages/react-dom/src/__tests__/ReactDOMFiber-test.js
+25
@@ -171,6 +171,31 @@ describe('ReactDOMFiber', () => {
171 expect(firstNode.tagName).toBe('DIV');
172 });
173
174 + it('renders an empty fragment', () => {
175 + const Div = () => <div />;
176 + const EmptyFragment = () => <React.Fragment />;
177 + const NonEmptyFragment = () => (
178 + <React.Fragment>
179 + <Div />
180 + </React.Fragment>
181 + );
182 +
183 + ReactDOM.render(<EmptyFragment />, container);
184 + expect(container.firstChild).toBe(null);
185 +
186 + ReactDOM.render(<NonEmptyFragment />, container);
187 + expect(container.firstChild.tagName).toBe('DIV');
188 +
189 + ReactDOM.render(<EmptyFragment />, container);
190 + expect(container.firstChild).toBe(null);
191 +
192 + ReactDOM.render(<Div />, container);
193 + expect(container.firstChild.tagName).toBe('DIV');
194 +
195 + ReactDOM.render(<EmptyFragment />, container);
196 + expect(container.firstChild).toBe(null);
197 + });
198 +
199 let svgEls, htmlEls, mathEls;
200 const expectSVG = {ref: el => svgEls.push(el)};
201 const expectHTML = {ref: el => htmlEls.push(el)};
packages/react-reconciler/src/ReactChildFiber.js
+4 -4
@@ -1208,12 +1208,12 @@ function ChildReconciler(shouldTrackSideEffects) {
1208 // Handle top level unkeyed fragments as if they were arrays.
1209 // This leads to an ambiguity between <>{[...]}</> and <>...</>.
1210 // We treat the ambiguous cases above the same.
1211 - if (
1211 + const isUnkeyedTopLevelFragment =
1212 typeof newChild === 'object' &&
1213 newChild !== null &&
1214 newChild.type === REACT_FRAGMENT_TYPE &&
1215 - newChild.key === null
1216 - ) {
1215 + newChild.key === null;
1216 + if (isUnkeyedTopLevelFragment) {
1217 newChild = newChild.props.children;
1218 }
1219
@@ -1281,7 +1281,7 @@ function ChildReconciler(shouldTrackSideEffects) {
1281 warnOnFunctionType();
1282 }
1283 }
1284 - if (typeof newChild === 'undefined') {
1284 + if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) {
1285 // If the new child is undefined, and the return fiber is a composite
1286 // component, throw an error. If Fiber return types are disabled,
1287 // we already threw above.