@samitouri / QOS-React / commits / af3603ea2f

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