ReactComponentTreeDevtool should ignore TopLevelWrapper
Dan Abramov committed
Apr 22, 2016 at 02:42 UTC
1ebffa59fe1c465bf10441334c2e60e7a76b32c2
4 files changed
+75
-40
src/isomorphic/ReactDebugTool.js
+3
@@ -58,6 +58,9 @@ var ReactDebugTool = {
58
onSetState() {
59
emitEvent('onSetState');
60
},
61
+ onSetIsTopLevelWrapper(debugID, isTopLevelWrapper) {
62
+ emitEvent('onSetIsTopLevelWrapper', debugID, isTopLevelWrapper);
63
+ },
64
onSetIsComposite(debugID, isComposite) {
65
emitEvent('onSetIsComposite', debugID, isComposite);
66
},
src/isomorphic/devtools/ReactComponentTreeDevtool.js
+46
-36
@@ -13,11 +13,15 @@
13
14
var invariant = require('invariant');
15
16
+var isTopLevelWrapperByID = {};
17
var unmountedContainerIDs = [];
18
var allChildIDsByContainerID = {};
19
var tree = {};
20
21
function updateTree(id, update) {
22
+ if (isTopLevelWrapperByID[id]) {
23
+ return;
24
+ }
25
if (!tree[id]) {
26
tree[id] = {};
27
}
@@ -44,6 +48,13 @@ function purgeTree(id) {
48
}
49
50
var ReactComponentTreeDevtool = {
51
+ onSetIsTopLevelWrapper(id, isTopLevelWrapper) {
52
+ if (isTopLevelWrapper) {
53
+ delete tree[id];
54
+ isTopLevelWrapperByID[id] = true;
55
+ }
56
+ },
57
+
58
onSetIsComposite(id, isComposite) {
59
updateTree(id, item => item.isComposite = isComposite);
60
},
@@ -53,45 +64,44 @@ var ReactComponentTreeDevtool = {
64
},
65
66
onSetChildren(id, nextChildIDs) {
56
- var prevChildIDs;
67
updateTree(id, item => {
58
- prevChildIDs = item.childIDs || [];
68
+ var prevChildIDs = item.childIDs || [];
69
item.childIDs = nextChildIDs;
60
- });
61
-
62
- prevChildIDs.forEach(prevChildID => {
63
- if (tree[prevChildID] && nextChildIDs.indexOf(prevChildID) === -1) {
64
- tree[prevChildID].parentID = null;
65
- }
66
- });
70
68
- nextChildIDs.forEach(nextChildID => {
69
- var item = tree[nextChildID];
70
-
71
- invariant(
72
- item,
73
- 'Expected devtool events to fire for the child ' +
74
- 'before its parent includes it in onSetChildren().'
75
- );
76
- invariant(
77
- item.isComposite != null,
78
- 'Expected onSetIsComposite() to fire for the child ' +
79
- 'before its parent includes it in onSetChildren().'
80
- );
81
- invariant(
82
- item.displayName != null,
83
- 'Expected onSetDisplayName() to fire for the child ' +
84
- 'before its parent includes it in onSetChildren().'
85
- );
86
- invariant(
87
- item.childIDs != null || item.text != null,
88
- 'Expected either onSetChildren() or onSetText() to fire for the child ' +
89
- 'before its parent includes it in onSetChildren().'
90
- );
91
-
92
- if (tree[nextChildID] && prevChildIDs.indexOf(nextChildID) === -1) {
93
- tree[nextChildID].parentID = id;
94
- }
71
+ prevChildIDs.forEach(prevChildID => {
72
+ var prevChild = tree[prevChildID];
73
+ if (prevChild && nextChildIDs.indexOf(prevChildID) === -1) {
74
+ prevChild.parentID = null;
75
+ }
76
+ });
77
+
78
+ nextChildIDs.forEach(nextChildID => {
79
+ var nextChild = tree[nextChildID];
80
+ invariant(
81
+ nextChild,
82
+ 'Expected devtool events to fire for the child ' +
83
+ 'before its parent includes it in onSetChildren().'
84
+ );
85
+ invariant(
86
+ nextChild.isComposite != null,
87
+ 'Expected onSetIsComposite() to fire for the child ' +
88
+ 'before its parent includes it in onSetChildren().'
89
+ );
90
+ invariant(
91
+ nextChild.displayName != null,
92
+ 'Expected onSetDisplayName() to fire for the child ' +
93
+ 'before its parent includes it in onSetChildren().'
94
+ );
95
+ invariant(
96
+ nextChild.childIDs != null || nextChild.text != null,
97
+ 'Expected either onSetChildren() or onSetText() to fire for the child ' +
98
+ 'before its parent includes it in onSetChildren().'
99
+ );
100
+
101
+ if (prevChildIDs.indexOf(nextChildID) === -1) {
102
+ nextChild.parentID = id;
103
+ }
104
+ });
105
});
106
},
107
src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js
+20
-4
@@ -36,7 +36,7 @@ describe('ReactComponentTreeDevtool', () => {
36
ReactDebugTool.removeDevtool(ReactComponentTreeDevtool);
37
});
38
39
- function denormalizeTree(
39
+ function explodeTree(
40
tree,
41
rootID,
42
includeOwner = false,
@@ -54,7 +54,7 @@ describe('ReactComponentTreeDevtool', () => {
54
55
if (item.childIDs) {
56
result.children = item.childIDs.map(childID =>
57
- denormalizeTree(tree, childID, includeOwner, rootID)
57
+ explodeTree(tree, childID, includeOwner, rootID)
58
);
59
}
60
if (item.text != null) {
@@ -89,7 +89,7 @@ describe('ReactComponentTreeDevtool', () => {
89
pairs.forEach(([element, expectedTree]) => {
90
currentElement = element;
91
ReactDOM.render(<Wrapper />, node);
92
- expect(denormalizeTree(
92
+ expect(explodeTree(
93
ReactComponentTreeDevtool.getTree(),
94
rootInstance._renderedComponent._debugID,
95
includeOwner
@@ -103,7 +103,7 @@ describe('ReactComponentTreeDevtool', () => {
103
pairs.forEach(([element, expectedTree]) => {
104
currentElement = element;
105
ReactDOMServer.renderToString(<Wrapper />);
106
- expect(denormalizeTree(
106
+ expect(explodeTree(
107
ReactComponentTreeDevtool.getTree(),
108
rootInstance._renderedComponent._debugID,
109
includeOwner
@@ -1831,4 +1831,20 @@ describe('ReactComponentTreeDevtool', () => {
1831
};
1832
assertTreeMatches([element, tree], true);
1833
});
1834
+
1835
+ it('ignores top-level wrapper', () => {
1836
+ var node = document.createElement('div');
1837
+ ReactDOM.render(<div className="a" />, node);
1838
+ expect(
1839
+ getRegisteredDisplayNames(ReactComponentTreeDevtool.getTree())
1840
+ ).toEqual(['div']);
1841
+ ReactDOM.render(<div className="b" />, node);
1842
+ expect(
1843
+ getRegisteredDisplayNames(ReactComponentTreeDevtool.getTree())
1844
+ ).toEqual(['div']);
1845
+ ReactDOM.unmountComponentAtNode(node);
1846
+ expect(
1847
+ getRegisteredDisplayNames(ReactComponentTreeDevtool.getTree())
1848
+ ).toEqual([]);
1849
+ });
1850
});
src/renderers/dom/client/ReactMount.js
+6
@@ -332,6 +332,12 @@ var ReactMount = {
332
333
ReactBrowserEventEmitter.ensureScrollValueMonitoring();
334
var componentInstance = instantiateReactComponent(nextElement);
335
+ if (__DEV__) {
336
+ ReactInstrumentation.debugTool.onSetIsTopLevelWrapper(
337
+ componentInstance._debugID,
338
+ true
339
+ );
340
+ }
341
342
// The initial render is synchronous but any updates that happen during
343
// rendering, in componentWillMount or componentDidMount, will be batched