Throw on invalid object type children
Same behavior as Stack
Andrew Clark committed
Jan 30, 2017 at 11:29 UTC
3089db94ceacc5792d811d24423349fbbbaf78a1
1 file changed
+45
-1
src/renderers/shared/fiber/ReactChildFiber.js
+45
-1
@@ -36,9 +36,11 @@ var emptyObject = require('emptyObject');
36
var getIteratorFn = require('getIteratorFn');
37
var invariant = require('invariant');
38
var ReactFeatureFlags = require('ReactFeatureFlags');
39
+var ReactCurrentOwner = require('ReactCurrentOwner');
40
41
if (__DEV__) {
42
var { getCurrentFiberStackAddendum } = require('ReactDebugCurrentFiber');
43
+ var { getComponentName } = require('ReactFiberTreeReflection');
44
var warning = require('warning');
45
}
46
@@ -107,6 +109,37 @@ function coerceRef(current: ?Fiber, element: ReactElement) {
109
return mixedRef;
110
}
111
112
+function throwOnInvalidObjectType(newChild : Object) {
113
+ const childrenString = String(newChild);
114
+ let addendum = '';
115
+ if (__DEV__) {
116
+ addendum =
117
+ ' If you meant to render a collection of children, use an array ' +
118
+ 'instead or wrap the object using createFragment(object) from the ' +
119
+ 'React add-ons.';
120
+ if (newChild._isReactElement) {
121
+ addendum =
122
+ ' It looks like you\'re using an element created by a different ' +
123
+ 'version of React. Make sure to use only one copy of React.';
124
+ }
125
+ if (ReactCurrentOwner.current) {
126
+ const owner : Fiber = (ReactCurrentOwner.current : any);
127
+ let name = getComponentName(owner);
128
+ if (name) {
129
+ addendum += ' Check the render method of `' + name + '`.';
130
+ }
131
+ }
132
+ }
133
+ invariant(
134
+ false,
135
+ 'Objects are not valid as a React child (found: %s).%s',
136
+ childrenString === '[object Object]' ?
137
+ 'object with keys {' + Object.keys(newChild).join(', ') + '}' :
138
+ childrenString,
139
+ addendum
140
+ );
141
+}
142
+
143
// This wrapper function exists because I expect to clone the code in each path
144
// to be able to optimize each path individually by branching early. This needs
145
// a compiler or we can do it manually. Helpers that don't need this branching
@@ -418,6 +451,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
451
created.return = returnFiber;
452
return created;
453
}
454
+
455
+ throwOnInvalidObjectType(newChild);
456
}
457
458
return null;
@@ -481,6 +516,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
516
}
517
return updateFragment(returnFiber, oldFiber, newChild, priority);
518
}
519
+
520
+ throwOnInvalidObjectType(newChild);
521
}
522
523
return null;
@@ -536,6 +573,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
573
const matchedFiber = existingChildren.get(newIdx) || null;
574
return updateFragment(returnFiber, matchedFiber, newChild, priority);
575
}
576
+
577
+ throwOnInvalidObjectType(newChild);
578
}
579
580
return null;
@@ -1083,7 +1122,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1122
const disableNewFiberFeatures = ReactFeatureFlags.disableNewFiberFeatures;
1123
1124
// Handle object types
1086
- if (typeof newChild === 'object' && newChild !== null) {
1125
+ const isObject = typeof newChild === 'object' && newChild !== null;
1126
+ if (isObject) {
1127
// Support only the subset of return types that Stack supports. Treat
1128
// everything else as empty, but log a warning.
1129
if (disableNewFiberFeatures) {
@@ -1199,6 +1239,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1239
);
1240
}
1241
1242
+ if (isObject) {
1243
+ throwOnInvalidObjectType(newChild);
1244
+ }
1245
+
1246
if (!disableNewFiberFeatures && typeof newChild === 'undefined') {
1247
// If the new child is undefined, and the return fiber is a composite
1248
// component, throw an error. If Fiber return types are disabled,