@samitouri / QOS-React / commits / 1ebffa59fe

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