cannot appear as a child of );
+ }).toThrow('Objects are not valid as a React child');
+ expect(() => {
+ ReactTestUtils.renderIntoDocument();
+ }).toThrow('Objects are not valid as a React child');
+ expect(() => {
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).toThrow('Objects are not valid as a React child');
+ expect(() => {
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).toThrow('Objects are not valid as a React child');
+ });
+
+ it('should support element-ish child', () => {
+ // This is similar to .
+ // It's important that we toString it.
+ let obj = {
+ $$typeof: Symbol.for('react.element'),
+ type: props => props.content,
+ ref: null,
+ key: null,
+ props: {
+ content: 'hello',
+ },
+ toString() {
+ return this.props.content;
+ },
+ };
+
+ let node = ReactTestUtils.renderIntoDocument();
+ expect(node.innerHTML).toBe('hello');
+
+ node = ReactTestUtils.renderIntoDocument();
+ expect(node.innerHTML).toBe('hello');
+
+ expect(() => {
+ node = ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ }).toWarnDev(
+ 'Only strings and numbers are supported as ,
+ );
+ expect(node.innerHTML).toBe('1hello2');
+ });
+
it('should be able to use dangerouslySetInnerHTML on option', () => {
let stub = ;
const node = ReactTestUtils.renderIntoDocument(stub);
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationForms-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationForms-test.js
index 6e2d95fe50e54..83cb86de5e2fa 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationForms-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationForms-test.js
@@ -439,7 +439,7 @@ describe('ReactDOMServerIntegration', () => {
);
expect(e.getAttribute('value')).toBe(null);
expect(e.getAttribute('defaultValue')).toBe(null);
- expect(e.firstChild.innerHTML).toBe('BarFooBaz');
+ expect(e.firstChild.innerHTML).toBe('BarFoo[object Object]Baz');
expect(e.firstChild.selected).toBe(true);
},
);
diff --git a/packages/react-dom/src/client/ReactDOMFiberOption.js b/packages/react-dom/src/client/ReactDOMFiberOption.js
index 9d905ceaaa018..117e679b531ac 100644
--- a/packages/react-dom/src/client/ReactDOMFiberOption.js
+++ b/packages/react-dom/src/client/ReactDOMFiberOption.js
@@ -9,23 +9,24 @@
import React from 'react';
import warning from 'shared/warning';
-import {validateDOMNesting, updatedAncestorInfo} from './validateDOMNesting';
import {getToStringValue, toString} from './ToStringValue';
let didWarnSelectedSetOnOption = false;
+let didWarnInvalidChild = false;
function flattenChildren(children) {
let content = '';
- // Flatten children and warn if they aren't strings or numbers;
- // invalid types are ignored.
+ // Flatten children. We'll warn if they are invalid
+ // during validateProps() which runs for hydration too.
+ // Note that this would throw on non-element objects.
+ // Elements are stringified (which is normally irrelevant
+ // but matters for ).
React.Children.forEach(children, function(child) {
if (child == null) {
return;
}
- if (typeof child === 'string' || typeof child === 'number') {
- content += child;
- }
+ content += child;
// Note: we don't warn about invalid children here.
// Instead, this is done separately below so that
// it happens during the hydration codepath too.
@@ -40,7 +41,10 @@ function flattenChildren(children) {
export function validateProps(element: Element, props: Object) {
if (__DEV__) {
- // Warn about invalid children, mirroring the logic above.
+ // This mirrors the codepath above, but runs for hydration too.
+ // Warn about invalid children here so that client and hydration are consistent.
+ // TODO: this seems like it could cause a DEV-only throw for hydration
+ // if children contains a non-element object. We should try to avoid that.
if (typeof props.children === 'object' && props.children !== null) {
React.Children.forEach(props.children, function(child) {
if (child == null) {
@@ -49,13 +53,16 @@ export function validateProps(element: Element, props: Object) {
if (typeof child === 'string' || typeof child === 'number') {
return;
}
- // This is not real ancestor info but it's close enough
- // to produce a useful warning for invalid children.
- // We don't have access to the real one because the