diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
index 859647b39c1ff..c41170aa54e91 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
@@ -924,33 +924,37 @@ describe('ReactDOMServerIntegration', () => {
);
});
- describe('components that throw errors', function() {
- itThrowsWhenRendering(
- 'a function returning undefined',
- async render => {
- const UndefinedComponent = () => undefined;
- await render(, 1);
- },
- 'UndefinedComponent(...): Nothing was returned from render. ' +
- 'This usually means a return statement is missing. Or, to ' +
- 'render nothing, return null.',
- );
+ describe('components that render nullish', function() {
+ itRenders('a function returning null', async render => {
+ const NullComponent = () => null;
+ await render();
+ });
- itThrowsWhenRendering(
- 'a class returning undefined',
- async render => {
- class UndefinedComponent extends React.Component {
- render() {
- return undefined;
- }
+ itRenders('a class returning null', async render => {
+ class NullComponent extends React.Component {
+ render() {
+ return null;
}
- await render(, 1);
- },
- 'UndefinedComponent(...): Nothing was returned from render. ' +
- 'This usually means a return statement is missing. Or, to ' +
- 'render nothing, return null.',
- );
+ }
+ await render();
+ });
+
+ itRenders('a function returning undefined', async render => {
+ const UndefinedComponent = () => undefined;
+ await render();
+ });
+
+ itRenders('a class returning undefined', async render => {
+ class UndefinedComponent extends React.Component {
+ render() {
+ return undefined;
+ }
+ }
+ await render();
+ });
+ });
+ describe('components that throw errors', function() {
itThrowsWhenRendering(
'a function returning an object',
async render => {
diff --git a/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js b/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
index 0c0b1d1a92739..12146e9b7edc5 100644
--- a/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
@@ -45,145 +45,117 @@ describe('ReactEmptyComponent', () => {
};
});
- it('should not produce child DOM nodes for null and false', () => {
- class Component1 extends React.Component {
- render() {
- return null;
- }
- }
-
- class Component2 extends React.Component {
- render() {
- return false;
+ describe.each([null, undefined])('when %s', nullORUndefined => {
+ it('should not throw when rendering', () => {
+ class Component extends React.Component {
+ render() {
+ return nullORUndefined;
+ }
}
- }
-
- const container1 = document.createElement('div');
- ReactDOM.render(, container1);
- expect(container1.children.length).toBe(0);
-
- const container2 = document.createElement('div');
- ReactDOM.render(, container2);
- expect(container2.children.length).toBe(0);
- });
-
- it('should still throw when rendering to undefined', () => {
- class Component extends React.Component {
- render() {}
- }
-
- expect(function() {
- ReactTestUtils.renderIntoDocument();
- }).toThrowError(
- 'Component(...): Nothing was returned from render. This usually means a return statement is missing. ' +
- 'Or, to render nothing, return null.',
- );
- });
- it('should be able to switch between rendering null and a normal tag', () => {
- const instance1 = (
-
- );
- const instance2 = (
-
- );
+ expect(function() {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrowError();
+ });
- ReactTestUtils.renderIntoDocument(instance1);
- ReactTestUtils.renderIntoDocument(instance2);
+ it('should not produce child DOM nodes for nullish and false', () => {
+ class Component1 extends React.Component {
+ render() {
+ return nullORUndefined;
+ }
+ }
- expect(log).toHaveBeenCalledTimes(4);
- expect(log).toHaveBeenNthCalledWith(1, null);
- expect(log).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({tagName: 'DIV'}),
- );
- expect(log).toHaveBeenNthCalledWith(
- 3,
- expect.objectContaining({tagName: 'DIV'}),
- );
- expect(log).toHaveBeenNthCalledWith(4, null);
- });
+ class Component2 extends React.Component {
+ render() {
+ return false;
+ }
+ }
- it('should be able to switch in a list of children', () => {
- const instance1 = (
-
- );
+ const container1 = document.createElement('div');
+ ReactDOM.render(, container1);
+ expect(container1.children.length).toBe(0);
- ReactTestUtils.renderIntoDocument(
-
- {instance1}
- {instance1}
- {instance1}
-
,
- );
+ const container2 = document.createElement('div');
+ ReactDOM.render(, container2);
+ expect(container2.children.length).toBe(0);
+ });
- expect(log).toHaveBeenCalledTimes(6);
- expect(log).toHaveBeenNthCalledWith(1, null);
- expect(log).toHaveBeenNthCalledWith(2, null);
- expect(log).toHaveBeenNthCalledWith(3, null);
- expect(log).toHaveBeenNthCalledWith(
- 4,
- expect.objectContaining({tagName: 'DIV'}),
- );
- expect(log).toHaveBeenNthCalledWith(
- 5,
- expect.objectContaining({tagName: 'DIV'}),
- );
- expect(log).toHaveBeenNthCalledWith(
- 6,
- expect.objectContaining({tagName: 'DIV'}),
- );
- });
-
- it('should distinguish between a script placeholder and an actual script tag', () => {
- const instance1 = (
-
- );
- const instance2 = (
-
- );
+ it('should be able to switch between rendering nullish and a normal tag', () => {
+ const instance1 = (
+
+ );
+ const instance2 = (
+
+ );
- expect(function() {
ReactTestUtils.renderIntoDocument(instance1);
- }).not.toThrow();
- expect(function() {
ReactTestUtils.renderIntoDocument(instance2);
- }).not.toThrow();
- expect(log).toHaveBeenCalledTimes(4);
- expect(log).toHaveBeenNthCalledWith(1, null);
- expect(log).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({tagName: 'SCRIPT'}),
- );
- expect(log).toHaveBeenNthCalledWith(
- 3,
- expect.objectContaining({tagName: 'SCRIPT'}),
- );
- expect(log).toHaveBeenNthCalledWith(4, null);
- });
+ expect(log).toHaveBeenCalledTimes(4);
+ expect(log).toHaveBeenNthCalledWith(1, null);
+ expect(log).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ expect(log).toHaveBeenNthCalledWith(
+ 3,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ expect(log).toHaveBeenNthCalledWith(4, null);
+ });
- it(
- 'should have findDOMNode return null when multiple layers of composite ' +
- 'components render to the same null placeholder',
- () => {
- class GrandChild extends React.Component {
- render() {
- return null;
- }
- }
+ it('should be able to switch in a list of children', () => {
+ const instance1 = (
+
+ );
- class Child extends React.Component {
- render() {
- return ;
- }
- }
+ ReactTestUtils.renderIntoDocument(
+
+ {instance1}
+ {instance1}
+ {instance1}
+
,
+ );
+
+ expect(log).toHaveBeenCalledTimes(6);
+ expect(log).toHaveBeenNthCalledWith(1, null);
+ expect(log).toHaveBeenNthCalledWith(2, null);
+ expect(log).toHaveBeenNthCalledWith(3, null);
+ expect(log).toHaveBeenNthCalledWith(
+ 4,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ expect(log).toHaveBeenNthCalledWith(
+ 5,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ expect(log).toHaveBeenNthCalledWith(
+ 6,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ });
+ it('should distinguish between a script placeholder and an actual script tag', () => {
const instance1 = (
-
+
);
const instance2 = (
-
+
);
expect(function() {
@@ -194,146 +166,192 @@ describe('ReactEmptyComponent', () => {
}).not.toThrow();
expect(log).toHaveBeenCalledTimes(4);
+ expect(log).toHaveBeenNthCalledWith(1, null);
expect(log).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({tagName: 'DIV'}),
+ 2,
+ expect.objectContaining({tagName: 'SCRIPT'}),
);
- expect(log).toHaveBeenNthCalledWith(2, null);
- expect(log).toHaveBeenNthCalledWith(3, null);
expect(log).toHaveBeenNthCalledWith(
- 4,
- expect.objectContaining({tagName: 'DIV'}),
+ 3,
+ expect.objectContaining({tagName: 'SCRIPT'}),
);
- },
- );
+ expect(log).toHaveBeenNthCalledWith(4, null);
+ });
+
+ it(
+ 'should have findDOMNode return null when multiple layers of composite ' +
+ 'components render to the same nullish placeholder',
+ () => {
+ class GrandChild extends React.Component {
+ render() {
+ return nullORUndefined;
+ }
+ }
- it('works when switching components', () => {
- let assertions = 0;
+ class Child extends React.Component {
+ render() {
+ return ;
+ }
+ }
- class Inner extends React.Component {
- render() {
- return ;
- }
+ const instance1 = (
+
+ );
+ const instance2 = (
+
+ );
- componentDidMount() {
- // Make sure the DOM node resolves properly even if we're replacing a
- // `null` component
- expect(ReactDOM.findDOMNode(this)).not.toBe(null);
- assertions++;
- }
+ expect(function() {
+ ReactTestUtils.renderIntoDocument(instance1);
+ }).not.toThrow();
+ expect(function() {
+ ReactTestUtils.renderIntoDocument(instance2);
+ }).not.toThrow();
+
+ expect(log).toHaveBeenCalledTimes(4);
+ expect(log).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ expect(log).toHaveBeenNthCalledWith(2, null);
+ expect(log).toHaveBeenNthCalledWith(3, null);
+ expect(log).toHaveBeenNthCalledWith(
+ 4,
+ expect.objectContaining({tagName: 'DIV'}),
+ );
+ },
+ );
- componentWillUnmount() {
- // Even though we're getting replaced by `null`, we haven't been
- // replaced yet!
- expect(ReactDOM.findDOMNode(this)).not.toBe(null);
- assertions++;
+ it('works when switching components', () => {
+ let assertions = 0;
+
+ class Inner extends React.Component {
+ render() {
+ return ;
+ }
+
+ componentDidMount() {
+ // Make sure the DOM node resolves properly even if we're replacing a
+ // `null` component
+ expect(ReactDOM.findDOMNode(this)).not.toBe(null);
+ assertions++;
+ }
+
+ componentWillUnmount() {
+ // Even though we're getting replaced by `null`, we haven't been
+ // replaced yet!
+ expect(ReactDOM.findDOMNode(this)).not.toBe(null);
+ assertions++;
+ }
}
- }
- class Wrapper extends React.Component {
- render() {
- return this.props.showInner ? : null;
+ class Wrapper extends React.Component {
+ render() {
+ return this.props.showInner ? : nullORUndefined;
+ }
}
- }
- const el = document.createElement('div');
- let component;
+ const el = document.createElement('div');
+ let component;
- // Render the component...
- component = ReactDOM.render(, el);
- expect(ReactDOM.findDOMNode(component)).not.toBe(null);
+ // Render the component...
+ component = ReactDOM.render(, el);
+ expect(ReactDOM.findDOMNode(component)).not.toBe(null);
- // Switch to null...
- component = ReactDOM.render(, el);
- expect(ReactDOM.findDOMNode(component)).toBe(null);
+ // Switch to null...
+ component = ReactDOM.render(, el);
+ expect(ReactDOM.findDOMNode(component)).toBe(null);
- // ...then switch back.
- component = ReactDOM.render(, el);
- expect(ReactDOM.findDOMNode(component)).not.toBe(null);
+ // ...then switch back.
+ component = ReactDOM.render(, el);
+ expect(ReactDOM.findDOMNode(component)).not.toBe(null);
- expect(assertions).toBe(3);
- });
+ expect(assertions).toBe(3);
+ });
- it('can render null at the top level', () => {
- const div = document.createElement('div');
- ReactDOM.render(null, div);
- expect(div.innerHTML).toBe('');
- });
+ it('can render nullish at the top level', () => {
+ const div = document.createElement('div');
+ ReactDOM.render(nullORUndefined, div);
+ expect(div.innerHTML).toBe('');
+ });
- it('does not break when updating during mount', () => {
- class Child extends React.Component {
- componentDidMount() {
- if (this.props.onMount) {
- this.props.onMount();
+ it('does not break when updating during mount', () => {
+ class Child extends React.Component {
+ componentDidMount() {
+ if (this.props.onMount) {
+ this.props.onMount();
+ }
}
- }
- render() {
- if (!this.props.visible) {
- return null;
- }
+ render() {
+ if (!this.props.visible) {
+ return nullORUndefined;
+ }
- return hello world
;
+ return hello world
;
+ }
}
- }
- class Parent extends React.Component {
- update = () => {
- this.forceUpdate();
- };
+ class Parent extends React.Component {
+ update = () => {
+ this.forceUpdate();
+ };
- render() {
- return (
-
-
-
-
-
- );
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
}
- }
- expect(function() {
- ReactTestUtils.renderIntoDocument();
- }).not.toThrow();
- });
+ expect(function() {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrow();
+ });
- it('preserves the dom node during updates', () => {
- class Empty extends React.Component {
- render() {
- return null;
+ it('preserves the dom node during updates', () => {
+ class Empty extends React.Component {
+ render() {
+ return nullORUndefined;
+ }
}
- }
- const container = document.createElement('div');
+ const container = document.createElement('div');
- ReactDOM.render(, container);
- const noscript1 = container.firstChild;
- expect(noscript1).toBe(null);
+ ReactDOM.render(, container);
+ const noscript1 = container.firstChild;
+ expect(noscript1).toBe(null);
- // This update shouldn't create a DOM node
- ReactDOM.render(, container);
- const noscript2 = container.firstChild;
- expect(noscript2).toBe(null);
- });
+ // This update shouldn't create a DOM node
+ ReactDOM.render(, container);
+ const noscript2 = container.firstChild;
+ expect(noscript2).toBe(null);
+ });
- it('should warn about React.forwardRef that returns undefined', () => {
- const Empty = () => {};
- const EmptyForwardRef = React.forwardRef(Empty);
+ it('should not warn about React.forwardRef that returns nullish', () => {
+ const Empty = () => {
+ return nullORUndefined;
+ };
+ const EmptyForwardRef = React.forwardRef(Empty);
- expect(() => {
- ReactTestUtils.renderIntoDocument();
- }).toThrowError(
- 'ForwardRef(Empty)(...): Nothing was returned from render.',
- );
- });
+ expect(() => {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrowError();
+ });
- it('should warn about React.memo that returns undefined', () => {
- const Empty = () => {};
- const EmptyMemo = React.memo(Empty);
+ it('should not warn about React.memo that returns nullish', () => {
+ const Empty = () => {
+ return nullORUndefined;
+ };
+ const EmptyMemo = React.memo(Empty);
- expect(() => {
- ReactTestUtils.renderIntoDocument();
- }).toThrowError('Empty(...): Nothing was returned from render.');
+ expect(() => {
+ ReactTestUtils.renderIntoDocument();
+ }).not.toThrowError();
+ });
});
});
diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
index 0aa9aa69285fa..9228316f884ee 100644
--- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
@@ -136,7 +136,7 @@ describe('ReactFunctionComponent', () => {
);
});
- it('should throw when stateless component returns undefined', () => {
+ it('should not throw when stateless component returns undefined', () => {
function NotAComponent() {}
expect(function() {
ReactTestUtils.renderIntoDocument(
@@ -144,10 +144,7 @@ describe('ReactFunctionComponent', () => {
,
);
- }).toThrowError(
- 'NotAComponent(...): Nothing was returned from render. ' +
- 'This usually means a return statement is missing. Or, to render nothing, return null.',
- );
+ }).not.toThrowError();
});
it('should throw on string refs in pure functions', () => {
diff --git a/packages/react-dom/src/__tests__/ReactMockedComponent-test.js b/packages/react-dom/src/__tests__/ReactMockedComponent-test.js
index c572c41197f2e..9d33a08ca9c9f 100644
--- a/packages/react-dom/src/__tests__/ReactMockedComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactMockedComponent-test.js
@@ -30,42 +30,18 @@ describe('ReactMockedComponent', () => {
MockedComponent.prototype.render = jest.fn();
});
- it('should allow a mocked component to be rendered in dev', () => {
+ it('should allow a mocked component to be rendered', () => {
const container = document.createElement('container');
- if (__DEV__) {
- ReactDOM.render(, container);
- } else {
- expect(() => ReactDOM.render(, container)).toThrow(
- 'Nothing was returned from render.',
- );
- }
+ ReactDOM.render(, container);
});
it('should allow a mocked component to be updated in dev', () => {
const container = document.createElement('container');
- if (__DEV__) {
- ReactDOM.render(, container);
- } else {
- expect(() => ReactDOM.render(, container)).toThrow(
- 'Nothing was returned from render.',
- );
- }
- if (__DEV__) {
- ReactDOM.render(, container);
- } else {
- expect(() => ReactDOM.render(, container)).toThrow(
- 'Nothing was returned from render.',
- );
- }
+ ReactDOM.render(, container);
+ ReactDOM.render(, container);
});
it('should allow a mocked component to be rendered in dev (SSR)', () => {
- if (__DEV__) {
- ReactDOMServer.renderToString();
- } else {
- expect(() => ReactDOMServer.renderToString()).toThrow(
- 'Nothing was returned from render.',
- );
- }
+ ReactDOMServer.renderToString();
});
});
diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
index 81be4cb30d72d..8714059bb3861 100644
--- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
+++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
@@ -242,7 +242,7 @@ module.exports = function(initModules) {
await asyncReactDOMRender(element, cleanContainer, true);
// This gives us the expected text content.
const cleanTextContent =
- cleanContainer.lastChild && cleanContainer.lastChild.textContent;
+ (cleanContainer.lastChild && cleanContainer.lastChild.textContent) || '';
// The only guarantee is that text content has been patched up if needed.
expect(hydratedTextContent).toBe(cleanTextContent);
diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js
index 752af3b2c7377..c19b8b78576b2 100644
--- a/packages/react-dom/src/server/ReactPartialRenderer.js
+++ b/packages/react-dom/src/server/ReactPartialRenderer.js
@@ -391,18 +391,6 @@ function createOpenTagMarkup(
return ret;
}
-function validateRenderResult(child, type) {
- if (child === undefined) {
- invariant(
- false,
- '%s(...): Nothing was returned from render. This usually means a ' +
- 'return statement is missing. Or, to render nothing, ' +
- 'return null.',
- getComponentNameFromType(type) || 'Component',
- );
- }
-}
-
function resolve(
child: mixed,
context: Object,
@@ -631,7 +619,6 @@ function resolve(
inst.render == null
) {
child = inst;
- validateRenderResult(child, Component);
return;
}
}
@@ -720,15 +707,6 @@ function resolve(
}
child = inst.render();
- if (__DEV__) {
- if (child === undefined && inst.render._isMockFunction) {
- // This is probably bad practice. Consider warning here and
- // deprecating this convenience.
- child = null;
- }
- }
- validateRenderResult(child, Component);
-
let childContext;
if (disableLegacyContext) {
if (__DEV__) {
diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js
index 024a903dbd915..e3f41115f53f9 100644
--- a/packages/react-reconciler/src/ReactChildFiber.new.js
+++ b/packages/react-reconciler/src/ReactChildFiber.new.js
@@ -21,15 +21,7 @@ import {
REACT_PORTAL_TYPE,
REACT_LAZY_TYPE,
} from 'shared/ReactSymbols';
-import {
- FunctionComponent,
- ClassComponent,
- HostText,
- HostPortal,
- ForwardRef,
- Fragment,
- SimpleMemoComponent,
-} from './ReactWorkTags';
+import {ClassComponent, HostText, HostPortal, Fragment} from './ReactWorkTags';
import invariant from 'shared/invariant';
import isArray from 'shared/isArray';
import {
@@ -1302,36 +1294,6 @@ function ChildReconciler(shouldTrackSideEffects) {
warnOnFunctionType(returnFiber);
}
}
- 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.
- switch (returnFiber.tag) {
- case ClassComponent: {
- if (__DEV__) {
- const instance = returnFiber.stateNode;
- if (instance.render._isMockFunction) {
- // We allow auto-mocks to proceed as if they're returning null.
- break;
- }
- }
- }
- // Intentionally fall through to the next case, which handles both
- // functions and classes
- // eslint-disable-next-lined no-fallthrough
- case FunctionComponent:
- case ForwardRef:
- case SimpleMemoComponent: {
- invariant(
- false,
- '%s(...): Nothing was returned from render. This usually means a ' +
- 'return statement is missing. Or, to render nothing, ' +
- 'return null.',
- getComponentNameFromFiber(returnFiber) || 'Component',
- );
- }
- }
- }
// Remaining cases are all treated as empty.
return deleteRemainingChildren(returnFiber, currentFirstChild);
diff --git a/packages/react-reconciler/src/ReactChildFiber.old.js b/packages/react-reconciler/src/ReactChildFiber.old.js
index 80b4fc35512d0..f1e39112b589b 100644
--- a/packages/react-reconciler/src/ReactChildFiber.old.js
+++ b/packages/react-reconciler/src/ReactChildFiber.old.js
@@ -21,15 +21,7 @@ import {
REACT_PORTAL_TYPE,
REACT_LAZY_TYPE,
} from 'shared/ReactSymbols';
-import {
- FunctionComponent,
- ClassComponent,
- HostText,
- HostPortal,
- ForwardRef,
- Fragment,
- SimpleMemoComponent,
-} from './ReactWorkTags';
+import {ClassComponent, HostText, HostPortal, Fragment} from './ReactWorkTags';
import invariant from 'shared/invariant';
import isArray from 'shared/isArray';
import {
@@ -1302,36 +1294,6 @@ function ChildReconciler(shouldTrackSideEffects) {
warnOnFunctionType(returnFiber);
}
}
- 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.
- switch (returnFiber.tag) {
- case ClassComponent: {
- if (__DEV__) {
- const instance = returnFiber.stateNode;
- if (instance.render._isMockFunction) {
- // We allow auto-mocks to proceed as if they're returning null.
- break;
- }
- }
- }
- // Intentionally fall through to the next case, which handles both
- // functions and classes
- // eslint-disable-next-lined no-fallthrough
- case FunctionComponent:
- case ForwardRef:
- case SimpleMemoComponent: {
- invariant(
- false,
- '%s(...): Nothing was returned from render. This usually means a ' +
- 'return statement is missing. Or, to render nothing, ' +
- 'return null.',
- getComponentNameFromFiber(returnFiber) || 'Component',
- );
- }
- }
- }
// Remaining cases are all treated as empty.
return deleteRemainingChildren(returnFiber, currentFirstChild);
diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js
index 9e2874eea4493..95074071da1d6 100644
--- a/packages/react-server/src/ReactFizzServer.js
+++ b/packages/react-server/src/ReactFizzServer.js
@@ -554,16 +554,6 @@ function shouldConstruct(Component) {
return Component.prototype && Component.prototype.isReactComponent;
}
-function invalidRenderResult(type: any): void {
- invariant(
- false,
- '%s(...): Nothing was returned from render. This usually means a ' +
- 'return statement is missing. Or, to render nothing, ' +
- 'return null.',
- getComponentNameFromType(type) || 'Component',
- );
-}
-
function renderWithHooks(
request: Request,
task: Task,
@@ -574,11 +564,7 @@ function renderWithHooks(
const componentIdentity = {};
prepareToUseHooks(componentIdentity);
const result = Component(props, secondArg);
- const children = finishHooks(Component, props, result, secondArg);
- if (children === undefined) {
- invalidRenderResult(Component);
- }
- return children;
+ return finishHooks(Component, props, result, secondArg);
}
function finishClassComponent(
@@ -589,13 +575,6 @@ function finishClassComponent(
props: any,
): ReactNodeList {
const nextChildren = instance.render();
- if (nextChildren === undefined) {
- if (__DEV__ && instance.render._isMockFunction) {
- // We allow auto-mocks to proceed as if they're returning null.
- } else {
- invalidRenderResult(Component);
- }
- }
if (__DEV__) {
if (instance.props !== props) {