diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt
index 7ab7803ab368..d14ca51e78db 100644
--- a/scripts/fiber/tests-failing.txt
+++ b/scripts/fiber/tests-failing.txt
@@ -1,8 +1,3 @@
-src/addons/__tests__/ReactFragment-test.js
-* should throw if a plain object is used as a child
-* should throw if a plain object even if it is in an owner
-* should throw if a plain object looks like an old element
-
src/isomorphic/classic/__tests__/ReactContextValidator-test.js
* should pass previous context to lifecycles
diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt
index a9d16d92ebc4..04c72a219f93 100644
--- a/scripts/fiber/tests-passing.txt
+++ b/scripts/fiber/tests-passing.txt
@@ -39,6 +39,8 @@ src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js
* does not do a deep comparison
src/addons/__tests__/ReactFragment-test.js
+* should throw if a plain object is used as a child
+* should throw if a plain object even if it is in an owner
* warns for numeric keys on objects as children
* should warn if passing null to createFragment
* should warn if passing an array to createFragment
diff --git a/src/addons/__tests__/ReactFragment-test.js b/src/addons/__tests__/ReactFragment-test.js
index 4788c06e2f3d..0f86093b7ba6 100644
--- a/src/addons/__tests__/ReactFragment-test.js
+++ b/src/addons/__tests__/ReactFragment-test.js
@@ -59,17 +59,6 @@ describe('ReactFragment', () => {
);
});
- it('should throw if a plain object looks like an old element', () => {
- var oldEl = {_isReactElement: true, type: 'span', props: {}};
- var container = document.createElement('div');
- expect(() => ReactDOM.render(
{oldEl}
, container)).toThrowError(
- 'Objects are not valid as a React child (found: object with keys ' +
- '{_isReactElement, type, props}). It looks like you\'re using an ' +
- 'element created by a different version of React. Make sure to use ' +
- 'only one copy of React.'
- );
- });
-
it('warns for numeric keys on objects as children', () => {
spyOn(console, 'error');
diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js
index 0505ae07e34c..db8be5c9f908 100644
--- a/src/renderers/shared/fiber/ReactChildFiber.js
+++ b/src/renderers/shared/fiber/ReactChildFiber.js
@@ -36,9 +36,11 @@ var emptyObject = require('emptyObject');
var getIteratorFn = require('getIteratorFn');
var invariant = require('invariant');
var ReactFeatureFlags = require('ReactFeatureFlags');
+var ReactCurrentOwner = require('ReactCurrentOwner');
if (__DEV__) {
var { getCurrentFiberStackAddendum } = require('ReactDebugCurrentFiber');
+ var { getComponentName } = require('ReactFiberTreeReflection');
var warning = require('warning');
}
@@ -107,6 +109,34 @@ function coerceRef(current: ?Fiber, element: ReactElement) {
return mixedRef;
}
+function throwOnInvalidObjectType(returnFiber : Fiber, newChild : Object) {
+ if (returnFiber.type !== 'textarea') {
+ const childrenString = String(newChild);
+ let addendum = '';
+ if (__DEV__) {
+ addendum =
+ ' If you meant to render a collection of children, use an array ' +
+ 'instead or wrap the object using createFragment(object) from the ' +
+ 'React add-ons.';
+ const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
+ if (owner && typeof owner.tag === 'number') {
+ const name = getComponentName((owner : any));
+ if (name) {
+ addendum += ' Check the render method of `' + name + '`.';
+ }
+ }
+ }
+ invariant(
+ false,
+ 'Objects are not valid as a React child (found: %s).%s',
+ childrenString === '[object Object]' ?
+ 'object with keys {' + Object.keys(newChild).join(', ') + '}' :
+ childrenString,
+ addendum
+ );
+ }
+}
+
// This wrapper function exists because I expect to clone the code in each path
// to be able to optimize each path individually by branching early. This needs
// a compiler or we can do it manually. Helpers that don't need this branching
@@ -418,6 +448,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
created.return = returnFiber;
return created;
}
+
+ throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
@@ -471,6 +503,14 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
return null;
}
}
+
+ case REACT_PORTAL_TYPE: {
+ if (newChild.key === key) {
+ return updatePortal(returnFiber, oldFiber, newChild, priority);
+ } else {
+ return null;
+ }
+ }
}
if (isArray(newChild) || getIteratorFn(newChild)) {
@@ -481,6 +521,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
return updateFragment(returnFiber, oldFiber, newChild, priority);
}
+
+ throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
@@ -536,6 +578,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
const matchedFiber = existingChildren.get(newIdx) || null;
return updateFragment(returnFiber, matchedFiber, newChild, priority);
}
+
+ throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
@@ -1083,7 +1127,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
const disableNewFiberFeatures = ReactFeatureFlags.disableNewFiberFeatures;
// Handle object types
- if (typeof newChild === 'object' && newChild !== null) {
+ const isObject = typeof newChild === 'object' && newChild !== null;
+ if (isObject) {
// Support only the subset of return types that Stack supports. Treat
// everything else as empty, but log a warning.
if (disableNewFiberFeatures) {
@@ -1199,6 +1244,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
);
}
+ if (isObject) {
+ throwOnInvalidObjectType(returnFiber, newChild);
+ }
+
if (!disableNewFiberFeatures && typeof newChild === 'undefined') {
// If the new child is undefined, and the return fiber is a composite
// component, throw an error. If Fiber return types are disabled,
diff --git a/src/shared/utils/traverseAllChildren.js b/src/shared/utils/traverseAllChildren.js
index 60b5f147aabf..9ea69721d07c 100644
--- a/src/shared/utils/traverseAllChildren.js
+++ b/src/shared/utils/traverseAllChildren.js
@@ -167,11 +167,6 @@ function traverseAllChildrenImpl(
' If you meant to render a collection of children, use an array ' +
'instead or wrap the object using createFragment(object) from the ' +
'React add-ons.';
- if (children._isReactElement) {
- addendum =
- ' It looks like you\'re using an element created by a different ' +
- 'version of React. Make sure to use only one copy of React.';
- }
if (ReactCurrentOwner.current) {
var name = ReactCurrentOwner.current.getName();
if (name) {