Skip to content

Commit ca92806

Browse files
committed
Add component stack to invalid-object-child error
https://twitter.com/EsaMatti/status/835952325525188608 (28 likes!)
1 parent 5cd44d2 commit ca92806

File tree

5 files changed

+54
-65
lines changed

5 files changed

+54
-65
lines changed

src/isomorphic/children/traverseAllChildren.js

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
'use strict';
1313

1414
var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
15-
var ReactCurrentOwner = require('ReactCurrentOwner');
1615

1716
var getIteratorFn = require('getIteratorFn');
1817
var invariant = require('fbjs/lib/invariant');
1918
var KeyEscapeUtils = require('KeyEscapeUtils');
2019
var warning = require('fbjs/lib/warning');
2120

21+
if (__DEV__) {
22+
var {
23+
getCurrentStackAddendum,
24+
} = require('ReactComponentTreeHook');
25+
}
26+
2227
var SEPARATOR = '.';
2328
var SUBSEPARATOR = ':';
2429

@@ -114,21 +119,12 @@ function traverseAllChildrenImpl(
114119
if (__DEV__) {
115120
// Warn about using Maps as children
116121
if (iteratorFn === children.entries) {
117-
let mapsAsChildrenAddendum = '';
118-
if (ReactCurrentOwner.current) {
119-
var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
120-
if (mapsAsChildrenOwnerName) {
121-
mapsAsChildrenAddendum = '\n\nCheck the render method of `' +
122-
mapsAsChildrenOwnerName +
123-
'`.';
124-
}
125-
}
126122
warning(
127123
didWarnAboutMaps,
128124
'Using Maps as children is unsupported and will likely yield ' +
129125
'unexpected results. Convert it to a sequence/iterable of keyed ' +
130126
'ReactElements instead.%s',
131-
mapsAsChildrenAddendum,
127+
getCurrentStackAddendum(),
132128
);
133129
didWarnAboutMaps = true;
134130
}
@@ -151,13 +147,7 @@ function traverseAllChildrenImpl(
151147
var addendum = '';
152148
if (__DEV__) {
153149
addendum = ' If you meant to render a collection of children, use an array ' +
154-
'instead.';
155-
if (ReactCurrentOwner.current) {
156-
var name = ReactCurrentOwner.current.getName();
157-
if (name) {
158-
addendum += '\n\nCheck the render method of `' + name + '`.';
159-
}
160-
}
150+
'instead.' + getCurrentStackAddendum();
161151
}
162152
var childrenString = '' + children;
163153
invariant(

src/renderers/__tests__/ReactComponent-test.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ var ReactDOMFeatureFlags;
1717
var ReactTestUtils;
1818

1919
describe('ReactComponent', () => {
20+
function normalizeCodeLocInfo(str) {
21+
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
22+
}
23+
2024
beforeEach(() => {
2125
React = require('react');
2226
ReactDOM = require('react-dom');
@@ -389,10 +393,19 @@ describe('ReactComponent', () => {
389393
};
390394
var element = <div>{[children]}</div>;
391395
var container = document.createElement('div');
392-
expect(() => ReactDOM.render(element, container)).toThrowError(
396+
var ex;
397+
try {
398+
ReactDOM.render(element, container);
399+
} catch (e) {
400+
ex = e;
401+
}
402+
expect(ex).toBeDefined();
403+
expect(normalizeCodeLocInfo(ex.message)).toBe(
393404
'Objects are not valid as a React child (found: object with keys ' +
394-
'{x, y, z}). If you meant to render a collection of children, use an ' +
395-
'array instead.',
405+
'{x, y, z}). If you meant to render a collection of children, use ' +
406+
'an array instead.' +
407+
// Fiber gives a slightly better stack with the nearest host components
408+
(ReactDOMFeatureFlags.useFiber ? '\n in div (at **)' : ''),
396409
);
397410
});
398411

@@ -408,10 +421,20 @@ describe('ReactComponent', () => {
408421
}
409422
}
410423
var container = document.createElement('div');
411-
expect(() => ReactDOM.render(<Foo />, container)).toThrowError(
424+
var ex;
425+
try {
426+
ReactDOM.render(<Foo />, container);
427+
} catch (e) {
428+
ex = e;
429+
}
430+
expect(ex).toBeDefined();
431+
expect(normalizeCodeLocInfo(ex.message)).toBe(
412432
'Objects are not valid as a React child (found: object with keys ' +
413-
'{a, b, c}). If you meant to render a collection of children, use an ' +
414-
'array instead.\n\nCheck the render method of `Foo`.',
433+
'{a, b, c}). If you meant to render a collection of children, use ' +
434+
'an array instead.\n' +
435+
// Fiber gives a slightly better stack with the nearest host components
436+
(ReactDOMFeatureFlags.useFiber ? ' in div (at **)\n' : '') +
437+
' in Foo (at **)',
415438
);
416439
});
417440
});

src/renderers/__tests__/ReactMultiChild-test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,15 @@ describe('ReactMultiChild', () => {
274274
var container = document.createElement('div');
275275
ReactDOM.render(<Parent />, container);
276276
expectDev(console.error.calls.count()).toBe(1);
277-
expectDev(console.error.calls.argsFor(0)[0]).toBe(
277+
expectDev(
278+
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
279+
).toBe(
278280
'Warning: Using Maps as children is unsupported and will likely yield ' +
279281
'unexpected results. Convert it to a sequence/iterable of keyed ' +
280-
'ReactElements instead.\n\nCheck the render method of `Parent`.',
282+
'ReactElements instead.\n' +
283+
// Fiber gives a slightly better stack with the nearest host components
284+
(ReactDOMFeatureFlags.useFiber ? ' in div (at **)\n' : '') +
285+
' in Parent (at **)'
281286
);
282287
});
283288

src/renderers/shared/fiber/ReactChildFiber.js

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,9 @@ var emptyObject = require('fbjs/lib/emptyObject');
3636
var getIteratorFn = require('getIteratorFn');
3737
var invariant = require('fbjs/lib/invariant');
3838
var ReactFeatureFlags = require('ReactFeatureFlags');
39-
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
4039

4140
if (__DEV__) {
4241
var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber');
43-
var getComponentName = require('getComponentName');
4442
var warning = require('fbjs/lib/warning');
4543
var didWarnAboutMaps = false;
4644
}
@@ -127,14 +125,7 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
127125
let addendum = '';
128126
if (__DEV__) {
129127
addendum = ' If you meant to render a collection of children, use an array ' +
130-
'instead.';
131-
const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
132-
if (owner && typeof owner.tag === 'number') {
133-
const name = getComponentName((owner: any));
134-
if (name) {
135-
addendum += '\n\nCheck the render method of `' + name + '`.';
136-
}
137-
}
128+
'instead.' + getCurrentFiberStackAddendum();
138129
}
139130
invariant(
140131
false,
@@ -813,22 +804,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
813804
if (typeof newChildrenIterable.entries === 'function') {
814805
const possibleMap = (newChildrenIterable: any);
815806
if (possibleMap.entries === iteratorFn) {
816-
let mapsAsChildrenAddendum = '';
817-
const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
818-
if (owner && typeof owner.tag === 'number') {
819-
const mapsAsChildrenOwnerName = getComponentName((owner: any));
820-
if (mapsAsChildrenOwnerName) {
821-
mapsAsChildrenAddendum = '\n\nCheck the render method of `' +
822-
mapsAsChildrenOwnerName +
823-
'`.';
824-
}
825-
}
826807
warning(
827808
didWarnAboutMaps,
828809
'Using Maps as children is unsupported and will likely yield ' +
829810
'unexpected results. Convert it to a sequence/iterable of keyed ' +
830811
'ReactElements instead.%s',
831-
mapsAsChildrenAddendum,
812+
getCurrentFiberStackAddendum()
832813
);
833814
didWarnAboutMaps = true;
834815
}

src/renderers/shared/stack/reconciler/traverseStackChildren.js

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
'use strict';
1313

1414
var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
15-
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
1615

1716
var getIteratorFn = require('getIteratorFn');
1817
var invariant = require('fbjs/lib/invariant');
1918
var KeyEscapeUtils = require('KeyEscapeUtils');
2019
var warning = require('fbjs/lib/warning');
2120

21+
if (__DEV__) {
22+
var {
23+
getCurrentStackAddendum,
24+
} = require('ReactGlobalSharedState').ReactComponentTreeHook;
25+
}
26+
2227
var SEPARATOR = '.';
2328
var SUBSEPARATOR = ':';
2429

@@ -114,21 +119,12 @@ function traverseStackChildrenImpl(
114119
if (__DEV__) {
115120
// Warn about using Maps as children
116121
if (iteratorFn === children.entries) {
117-
let mapsAsChildrenAddendum = '';
118-
if (ReactCurrentOwner.current) {
119-
var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
120-
if (mapsAsChildrenOwnerName) {
121-
mapsAsChildrenAddendum = '\n\nCheck the render method of `' +
122-
mapsAsChildrenOwnerName +
123-
'`.';
124-
}
125-
}
126122
warning(
127123
didWarnAboutMaps,
128124
'Using Maps as children is unsupported and will likely yield ' +
129125
'unexpected results. Convert it to a sequence/iterable of keyed ' +
130126
'ReactElements instead.%s',
131-
mapsAsChildrenAddendum,
127+
getCurrentStackAddendum(),
132128
);
133129
didWarnAboutMaps = true;
134130
}
@@ -151,13 +147,7 @@ function traverseStackChildrenImpl(
151147
var addendum = '';
152148
if (__DEV__) {
153149
addendum = ' If you meant to render a collection of children, use an array ' +
154-
'instead.';
155-
if (ReactCurrentOwner.current) {
156-
var name = ReactCurrentOwner.current.getName();
157-
if (name) {
158-
addendum += '\n\nCheck the render method of `' + name + '`.';
159-
}
160-
}
150+
'instead.' + getCurrentStackAddendum();
161151
}
162152
var childrenString = '' + children;
163153
invariant(

0 commit comments

Comments
 (0)