Skip to content

Commit

Permalink
Prevent infinite loop when SSR-rendering a portal (#11709)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon authored Nov 29, 2017
1 parent e0c3113 commit c3f1b6c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 1 deletion.
34 changes: 34 additions & 0 deletions packages/react-dom/src/__tests__/ReactServerRendering-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
'use strict';

var React;
var ReactCallReturn;
var ReactDOM;
var ReactDOMServer;
var ReactTestUtils;
Expand All @@ -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');
Expand Down Expand Up @@ -772,4 +774,36 @@ describe('ReactDOMServer', () => {
);
}
});

it('should throw rendering portals on the server', () => {
var div = document.createElement('div');
expect(() => {
ReactDOMServer.renderToString(
<div>{ReactDOM.createPortal(<div />, div)}</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(
<div>{ReactCallReturn.unstable_createReturn(42)}</div>,
);
}).toThrow(
'The experimental Call and Return types are not currently supported by the server renderer.',
);
expect(() => {
ReactDOMServer.renderToString(
<div>
{ReactCallReturn.unstable_createCall(null, function() {}, {})}
</div>,
);
}).toThrow(
'The experimental Call and Return types are not currently supported by the server renderer.',
);
});
});
28 changes: 27 additions & 1 deletion packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit c3f1b6c

Please sign in to comment.