Devtools should be able to clean up the tree on client rendering
Dan Abramov committed
Apr 20, 2016 at 19:01 UTC
af3603ea2f7fb3cad5632a4e6ae9b4fcc579f91e
5 files changed
+89
-45
src/isomorphic/ReactDebugTool.js
+8
-8
@@ -73,17 +73,17 @@ var ReactDebugTool = {
73
onSetText(debugID, text) {
74
emitEvent('onSetText', debugID, text);
75
},
76
- onMountRootComponent(internalInstance) {
77
- emitEvent('onMountRootComponent', internalInstance);
76
+ onMountRootComponent(debugID) {
77
+ emitEvent('onMountRootComponent', debugID);
78
},
79
- onMountComponent(internalInstance) {
80
- emitEvent('onMountComponent', internalInstance);
79
+ onMountComponent(debugID) {
80
+ emitEvent('onMountComponent', debugID);
81
},
82
- onUpdateComponent(internalInstance) {
83
- emitEvent('onUpdateComponent', internalInstance);
82
+ onUpdateComponent(debugID) {
83
+ emitEvent('onUpdateComponent', debugID);
84
},
85
- onUnmountComponent(internalInstance) {
86
- emitEvent('onUnmountComponent', internalInstance);
85
+ onUnmountComponent(debugID) {
86
+ emitEvent('onUnmountComponent', debugID);
87
},
88
};
89
src/isomorphic/__tests__/ReactDebugTool-test.js
+53
-22
@@ -22,22 +22,22 @@ describe('ReactDebugTool', () => {
22
function createDevtool() {
23
var tree = {};
24
25
- function updateTree(debugID, update) {
26
- if (!tree[debugID]) {
27
- tree[debugID] = {};
25
+ function updateTree(id, update) {
26
+ if (!tree[id]) {
27
+ tree[id] = {};
28
}
29
- update(tree[debugID]);
29
+ update(tree[id]);
30
}
31
32
- function getTree(debugID, includeOwner) {
33
- var item = tree[debugID];
32
+ function getTree(id, includeOwner) {
33
+ var item = tree[id];
34
var result = {
35
isComposite: item.isComposite,
36
displayName: item.displayName,
37
};
38
- if (item.childDebugIDs) {
39
- result.children = item.childDebugIDs.map(childDebugID =>
40
- getTree(childDebugID, includeOwner)
38
+ if (item.childIDs) {
39
+ result.children = item.childIDs.map(childID =>
40
+ getTree(childID, includeOwner)
41
);
42
}
43
if (item.text != null) {
@@ -49,29 +49,57 @@ describe('ReactDebugTool', () => {
49
return result;
50
}
51
52
+ function purgeTree(id) {
53
+ var item = tree[id];
54
+ if (!item) {
55
+ return;
56
+ }
57
+
58
+ var {childIDs} = item;
59
+ delete tree[id];
60
+
61
+ if (childIDs) {
62
+ childIDs.forEach(purgeTree);
63
+ }
64
+ }
65
+
66
return {
53
- onSetIsComposite(debugID, isComposite) {
54
- updateTree(debugID, item => item.isComposite = isComposite);
67
+ onSetIsComposite(id, isComposite) {
68
+ updateTree(id, item => item.isComposite = isComposite);
69
},
56
- onSetDisplayName(debugID, displayName) {
57
- updateTree(debugID, item => item.displayName = displayName);
70
+
71
+ onSetDisplayName(id, displayName) {
72
+ updateTree(id, item => item.displayName = displayName);
73
},
59
- onSetChildren(debugID, childDebugIDs) {
60
- childDebugIDs.forEach(childDebugID => {
61
- var childItem = tree[childDebugID];
74
+
75
+ onSetChildren(id, childIDs) {
76
+ childIDs.forEach(childID => {
77
+ var childItem = tree[childID];
78
expect(childItem).toBeDefined();
79
expect(childItem.isComposite).toBeDefined();
80
expect(childItem.displayName).toBeDefined();
65
- expect(childItem.childDebugIDs || childItem.text).toBeDefined();
81
+ expect(childItem.childIDs || childItem.text).toBeDefined();
82
});
67
- updateTree(debugID, item => item.childDebugIDs = childDebugIDs);
83
+
84
+ updateTree(id, item => item.childIDs = childIDs);
85
},
69
- onSetOwner(debugID, ownerDebugID) {
70
- updateTree(debugID, item => item.ownerDebugID = ownerDebugID);
86
+
87
+ onSetOwner(id, ownerDebugID) {
88
+ updateTree(id, item => item.ownerDebugID = ownerDebugID);
89
+ },
90
+
91
+ onSetText(id, text) {
92
+ updateTree(id, item => item.text = text);
93
+ },
94
+
95
+ onUnmountComponent(id) {
96
+ purgeTree(id);
97
},
72
- onSetText(debugID, text) {
73
- updateTree(debugID, item => item.text = text);
98
+
99
+ getRegisteredDebugIDs() {
100
+ return Object.keys(tree);
101
},
102
+
103
getTree(rootDebugID, includeOwner) {
104
return getTree(rootDebugID, includeOwner);
105
},
@@ -119,6 +147,9 @@ describe('ReactDebugTool', () => {
147
);
148
expect(actualTree).toEqual(expectedTree);
149
});
150
+
151
+ ReactDOM.unmountComponentAtNode(node);
152
+ expect(devtool.getRegisteredDebugIDs()).toEqual([]);
153
}
154
155
describe('mount', () => {
src/renderers/dom/client/ReactMount.js
+1
-1
@@ -349,7 +349,7 @@ var ReactMount = {
349
instancesByReactRootID[wrapperID] = componentInstance;
350
351
if (__DEV__) {
352
- ReactInstrumentation.debugTool.onMountRootComponent(componentInstance);
352
+ ReactInstrumentation.debugTool.onMountRootComponent(componentInstance._debugID);
353
}
354
355
return componentInstance;
src/renderers/dom/shared/ReactDOMComponent.js
+23
-10
@@ -453,6 +453,7 @@ function ReactDOMComponent(element) {
453
this._flags = 0;
454
if (__DEV__) {
455
this._ancestorInfo = null;
456
+ this._contentDebugID = null;
457
}
458
}
459
@@ -758,11 +759,11 @@ ReactDOMComponent.Mixin = {
759
if (contentToUse != null) {
760
// TODO: Validate that text is allowed as a child of this node
761
if (__DEV__) {
761
- var inlinedTextDebugID = this._debugID + '#text';
762
- ReactInstrumentation.debugTool.onSetIsComposite(inlinedTextDebugID, false);
763
- ReactInstrumentation.debugTool.onSetDisplayName(inlinedTextDebugID, '#text');
764
- ReactInstrumentation.debugTool.onSetText(inlinedTextDebugID, '' + contentToUse);
765
- ReactInstrumentation.debugTool.onSetChildren(this._debugID, [inlinedTextDebugID]);
762
+ this._contentDebugID = this._debugID + '#text';
763
+ ReactInstrumentation.debugTool.onSetIsComposite(this._contentDebugID, false);
764
+ ReactInstrumentation.debugTool.onSetDisplayName(this._contentDebugID, '#text');
765
+ ReactInstrumentation.debugTool.onSetText(this._contentDebugID, '' + contentToUse);
766
+ ReactInstrumentation.debugTool.onSetChildren(this._debugID, [this._contentDebugID]);
767
}
768
DOMLazyTree.queueText(lazyTree, contentToUse);
769
} else if (childrenToUse != null) {
@@ -1020,11 +1021,11 @@ ReactDOMComponent.Mixin = {
1021
if (lastContent !== nextContent) {
1022
this.updateTextContent('' + nextContent);
1023
if (__DEV__) {
1023
- var inlinedTextDebugID = this._debugID + '#text';
1024
- ReactInstrumentation.debugTool.onSetIsComposite(inlinedTextDebugID, false);
1025
- ReactInstrumentation.debugTool.onSetDisplayName(inlinedTextDebugID, '#text');
1026
- ReactInstrumentation.debugTool.onSetText(inlinedTextDebugID, '' + nextContent);
1027
- ReactInstrumentation.debugTool.onSetChildren(this._debugID, [inlinedTextDebugID]);
1024
+ this._contentDebugID = this._debugID + '#text';
1025
+ ReactInstrumentation.debugTool.onSetIsComposite(this._contentDebugID, false);
1026
+ ReactInstrumentation.debugTool.onSetDisplayName(this._contentDebugID, '#text');
1027
+ ReactInstrumentation.debugTool.onSetText(this._contentDebugID, '' + nextContent);
1028
+ ReactInstrumentation.debugTool.onSetChildren(this._debugID, [this._contentDebugID]);
1029
}
1030
}
1031
} else if (nextHtml != null) {
@@ -1035,6 +1036,13 @@ ReactDOMComponent.Mixin = {
1036
ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
1037
}
1038
} else if (nextChildren != null) {
1039
+ if (__DEV__) {
1040
+ if (this._contentDebugID) {
1041
+ ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID);
1042
+ this._contentDebugID = null;
1043
+ }
1044
+ }
1045
+
1046
this.updateChildren(nextChildren, transaction, context);
1047
}
1048
},
@@ -1096,6 +1104,11 @@ ReactDOMComponent.Mixin = {
1104
this._rootNodeID = null;
1105
this._domID = null;
1106
this._wrapperState = null;
1107
+
1108
+ if (this._contentDebugID) {
1109
+ ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID);
1110
+ this._contentDebugID = null;
1111
+ }
1112
},
1113
1114
getPublicInstance: function() {
src/renderers/shared/reconciler/ReactReconciler.js
+4
-4
@@ -53,7 +53,7 @@ var ReactReconciler = {
53
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
54
}
55
if (__DEV__) {
56
- ReactInstrumentation.debugTool.onMountComponent(internalInstance);
56
+ ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID);
57
}
58
return markup;
59
},
@@ -76,7 +76,7 @@ var ReactReconciler = {
76
ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
77
internalInstance.unmountComponent(safely);
78
if (__DEV__) {
79
- ReactInstrumentation.debugTool.onUnmountComponent(internalInstance);
79
+ ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID);
80
}
81
},
82
@@ -128,7 +128,7 @@ var ReactReconciler = {
128
}
129
130
if (__DEV__) {
131
- ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
131
+ ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
132
}
133
},
134
@@ -145,7 +145,7 @@ var ReactReconciler = {
145
) {
146
internalInstance.performUpdateIfNecessary(transaction);
147
if (__DEV__) {
148
- ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
148
+ ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
149
}
150
},
151