diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js
index 12294a9e699ee..9bb4c6129444e 100644
--- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js
+++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js
@@ -10,6 +10,7 @@
'use strict';
var React;
+var ReactCallReturn;
var ReactDOM;
var ReactDOMServer;
var ReactTestUtils;
@@ -23,6 +24,7 @@ describe('ReactDOMServer', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
+ ReactCallReturn = require('react-call-return');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
PropTypes = require('prop-types');
@@ -772,4 +774,36 @@ describe('ReactDOMServer', () => {
);
}
});
+
+ it('should throw rendering portals on the server', () => {
+ var div = document.createElement('div');
+ expect(() => {
+ ReactDOMServer.renderToString(
+
{ReactDOM.createPortal(
, div)}
,
+ );
+ }).toThrow(
+ 'Portals are not currently supported by the server renderer. ' +
+ 'Render them conditionally so that they only appear on the client render.',
+ );
+ });
+
+ it('should throw rendering call/return on the server', () => {
+ var div = document.createElement('div');
+ expect(() => {
+ ReactDOMServer.renderToString(
+ {ReactCallReturn.unstable_createReturn(42)}
,
+ );
+ }).toThrow(
+ 'The experimental Call and Return types are not currently supported by the server renderer.',
+ );
+ expect(() => {
+ ReactDOMServer.renderToString(
+
+ {ReactCallReturn.unstable_createCall(null, function() {}, {})}
+
,
+ );
+ }).toThrow(
+ 'The experimental Call and Return types are not currently supported by the server renderer.',
+ );
+ });
});
diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js
index c76a311aac3b7..e05ccec206941 100644
--- a/packages/react-dom/src/server/ReactPartialRenderer.js
+++ b/packages/react-dom/src/server/ReactPartialRenderer.js
@@ -19,7 +19,12 @@ import warning from 'fbjs/lib/warning';
import checkPropTypes from 'prop-types/checkPropTypes';
import describeComponentFrame from 'shared/describeComponentFrame';
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
-import {REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
+import {
+ REACT_FRAGMENT_TYPE,
+ REACT_CALL_TYPE,
+ REACT_RETURN_TYPE,
+ REACT_PORTAL_TYPE,
+} from 'shared/ReactSymbols';
import {
createMarkupForCustomAttribute,
@@ -585,6 +590,27 @@ class ReactDOMServerRenderer {
if (nextChild === null || nextChild === false) {
return '';
} else if (!React.isValidElement(nextChild)) {
+ if (nextChild != null && nextChild.$$typeof != null) {
+ // Catch unexpected special types early.
+ const $$typeof = nextChild.$$typeof;
+ invariant(
+ $$typeof !== REACT_PORTAL_TYPE,
+ 'Portals are not currently supported by the server renderer. ' +
+ 'Render them conditionally so that they only appear on the client render.',
+ );
+ invariant(
+ $$typeof !== REACT_CALL_TYPE && $$typeof !== REACT_RETURN_TYPE,
+ 'The experimental Call and Return types are not currently ' +
+ 'supported by the server renderer.',
+ );
+ // Catch-all to prevent an infinite loop if React.Children.toArray() supports some new type.
+ invariant(
+ false,
+ 'Unknown element-like object type: %s. This is likely a bug in React. ' +
+ 'Please file an issue.',
+ ($$typeof: any).toString(),
+ );
+ }
const nextChildren = toArray(nextChild);
const frame: Frame = {
domNamespace: parentNamespace,