From 3089db94ceacc5792d811d24423349fbbbaf78a1 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Mon, 30 Jan 2017 11:29:14 -0800 Subject: [PATCH] Throw on invalid object type children Same behavior as Stack --- src/renderers/shared/fiber/ReactChildFiber.js | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index 0505ae07e3..e40a48c564 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,37 @@ function coerceRef(current: ?Fiber, element: ReactElement) { return mixedRef; } +function throwOnInvalidObjectType(newChild : Object) { + 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.'; + if (newChild._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) { + const owner : Fiber = (ReactCurrentOwner.current : any); + let name = getComponentName(owner); + 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 +451,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { created.return = returnFiber; return created; } + + throwOnInvalidObjectType(newChild); } return null; @@ -481,6 +516,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { } return updateFragment(returnFiber, oldFiber, newChild, priority); } + + throwOnInvalidObjectType(newChild); } return null; @@ -536,6 +573,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { const matchedFiber = existingChildren.get(newIdx) || null; return updateFragment(returnFiber, matchedFiber, newChild, priority); } + + throwOnInvalidObjectType(newChild); } return null; @@ -1083,7 +1122,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 +1239,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { ); } + if (isObject) { + throwOnInvalidObjectType(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,