Remove unnecessary indirection and events from the hooks (#7464)
* Remove unnecessary indirection from the tree hook * Replace onSetDisplayName, onSetOwner, onSetText with one event Less events is better. onSetDisplayName, onSetOwner, and onSetText only existed because we didn't initially track elements. * Remove unused variables
Dan Abramov committed
Aug 11, 2016 at 00:19 UTC
1f31357a2e6643ae3ff8e8a583a2c773d7b2209e
7 files changed
+108
-137
src/isomorphic/hooks/ReactComponentTreeHook.js
+101
-77
@@ -39,21 +39,16 @@ function remove(id) {
39
delete itemByKey[key];
40
}
41
42
-function update(id, updater) {
42
+function create(id, element) {
43
var key = getKeyFromID(id);
44
- if (!itemByKey[key]) {
45
- itemByKey[key] = {
46
- element: null,
47
- parentID: null,
48
- ownerID: null,
49
- text: null,
50
- childIDs: [],
51
- displayName: 'Unknown',
52
- isMounted: false,
53
- updateCount: 0,
54
- };
55
- }
56
- updater(itemByKey[key]);
44
+ itemByKey[key] = {
45
+ element,
46
+ parentID: null,
47
+ text: null,
48
+ childIDs: [],
49
+ isMounted: false,
50
+ updateCount: 0,
51
+ };
52
}
53
54
function purgeDeep(id) {
@@ -76,6 +71,18 @@ function describeComponentFrame(name, source, ownerName) {
71
);
72
}
73
74
+function getDisplayName(element) {
75
+ if (element == null) {
76
+ return '#empty';
77
+ } else if (typeof element === 'string' || typeof element === 'number') {
78
+ return '#text';
79
+ } else if (typeof element.type === 'string') {
80
+ return element.type;
81
+ } else {
82
+ return element.type.displayName || element.type.name || 'Unknown';
83
+ }
84
+}
85
+
86
function describeID(id) {
87
var name = ReactComponentTreeHook.getDisplayName(id);
88
var element = ReactComponentTreeHook.getElement(id);
@@ -94,76 +101,74 @@ function describeID(id) {
101
}
102
103
var ReactComponentTreeHook = {
97
- onSetDisplayName(id, displayName) {
98
- update(id, item => item.displayName = displayName);
99
- },
100
-
104
onSetChildren(id, nextChildIDs) {
102
- update(id, item => {
103
- item.childIDs = nextChildIDs;
104
-
105
- nextChildIDs.forEach(nextChildID => {
106
- var nextChild = get(nextChildID);
107
- invariant(
108
- nextChild,
109
- 'Expected hook events to fire for the child ' +
110
- 'before its parent includes it in onSetChildren().'
111
- );
112
- invariant(
113
- nextChild.displayName != null,
114
- 'Expected onSetDisplayName() to fire for the child ' +
115
- 'before its parent includes it in onSetChildren().'
116
- );
117
- invariant(
118
- nextChild.childIDs != null || nextChild.text != null,
119
- 'Expected onSetChildren() or onSetText() to fire for the child ' +
120
- 'before its parent includes it in onSetChildren().'
121
- );
122
- invariant(
123
- nextChild.isMounted,
124
- 'Expected onMountComponent() to fire for the child ' +
125
- 'before its parent includes it in onSetChildren().'
126
- );
127
- if (nextChild.parentID == null) {
128
- nextChild.parentID = id;
129
- // TODO: This shouldn't be necessary but mounting a new root during in
130
- // componentWillMount currently causes not-yet-mounted components to
131
- // be purged from our tree data so their parent ID is missing.
132
- }
133
- invariant(
134
- nextChild.parentID === id,
135
- 'Expected onSetParent() and onSetChildren() to be consistent (%s ' +
136
- 'has parents %s and %s).',
137
- nextChildID,
138
- nextChild.parentID,
139
- id
140
- );
141
- });
142
- });
143
- },
144
-
145
- onSetOwner(id, ownerID) {
146
- update(id, item => item.ownerID = ownerID);
105
+ var item = get(id);
106
+ item.childIDs = nextChildIDs;
107
+
108
+ for (var i = 0; i < nextChildIDs.length; i++) {
109
+ var nextChildID = nextChildIDs[i];
110
+ var nextChild = get(nextChildID);
111
+ invariant(
112
+ nextChild,
113
+ 'Expected hook events to fire for the child ' +
114
+ 'before its parent includes it in onSetChildren().'
115
+ );
116
+ invariant(
117
+ nextChild.childIDs != null ||
118
+ typeof nextChild.element !== 'object' ||
119
+ nextChild.element == null,
120
+ 'Expected onSetChildren() to fire for a container child ' +
121
+ 'before its parent includes it in onSetChildren().'
122
+ );
123
+ invariant(
124
+ nextChild.isMounted,
125
+ 'Expected onMountComponent() to fire for the child ' +
126
+ 'before its parent includes it in onSetChildren().'
127
+ );
128
+ if (nextChild.parentID == null) {
129
+ nextChild.parentID = id;
130
+ // TODO: This shouldn't be necessary but mounting a new root during in
131
+ // componentWillMount currently causes not-yet-mounted components to
132
+ // be purged from our tree data so their parent ID is missing.
133
+ }
134
+ invariant(
135
+ nextChild.parentID === id,
136
+ 'Expected onSetParent() and onSetChildren() to be consistent (%s ' +
137
+ 'has parents %s and %s).',
138
+ nextChildID,
139
+ nextChild.parentID,
140
+ id
141
+ );
142
+ }
143
},
144
145
onSetParent(id, parentID) {
150
- update(id, item => item.parentID = parentID);
146
+ var item = get(id);
147
+ item.parentID = parentID;
148
},
149
153
- onSetText(id, text) {
154
- update(id, item => item.text = text);
150
+ onInstantiateComponent(id, element) {
151
+ create(id, element);
152
},
153
154
onBeforeMountComponent(id, element) {
158
- update(id, item => item.element = element);
155
+ var item = get(id);
156
+ item.element = element;
157
},
158
159
onBeforeUpdateComponent(id, element) {
162
- update(id, item => item.element = element);
160
+ var item = get(id);
161
+ if (!item || !item.isMounted) {
162
+ // We may end up here as a result of setState() in componentWillUnmount().
163
+ // In this case, ignore the element.
164
+ return;
165
+ }
166
+ item.element = element;
167
},
168
169
onMountComponent(id) {
166
- update(id, item => item.isMounted = true);
170
+ var item = get(id);
171
+ item.isMounted = true;
172
},
173
174
onMountRootComponent(id) {
@@ -171,11 +176,18 @@ var ReactComponentTreeHook = {
176
},
177
178
onUpdateComponent(id) {
174
- update(id, item => item.updateCount++);
179
+ var item = get(id);
180
+ if (!item || !item.isMounted) {
181
+ // We may end up here as a result of setState() in componentWillUnmount().
182
+ // In this case, ignore the element.
183
+ return;
184
+ }
185
+ item.updateCount++;
186
},
187
188
onUnmountComponent(id) {
178
- update(id, item => item.isMounted = false);
189
+ var item = get(id);
190
+ item.isMounted = false;
191
unmountedIDs[id] = true;
192
delete rootIDs[id];
193
},
@@ -234,8 +246,11 @@ var ReactComponentTreeHook = {
246
},
247
248
getDisplayName(id) {
237
- var item = get(id);
238
- return item ? item.displayName : 'Unknown';
249
+ var element = ReactComponentTreeHook.getElement(id);
250
+ if (!element) {
251
+ return null;
252
+ }
253
+ return getDisplayName(element);
254
},
255
256
getElement(id) {
@@ -244,8 +259,11 @@ var ReactComponentTreeHook = {
259
},
260
261
getOwnerID(id) {
247
- var item = get(id);
248
- return item ? item.ownerID : null;
262
+ var element = ReactComponentTreeHook.getElement(id);
263
+ if (!element || !element._owner) {
264
+ return null;
265
+ }
266
+ return element._owner._debugID;
267
},
268
269
getParentID(id) {
@@ -261,8 +279,14 @@ var ReactComponentTreeHook = {
279
},
280
281
getText(id) {
264
- var item = get(id);
265
- return item ? item.text : null;
282
+ var element = ReactComponentTreeHook.getElement(id);
283
+ if (typeof element === 'string') {
284
+ return element;
285
+ } else if (typeof element === 'number') {
286
+ return '' + element;
287
+ } else {
288
+ return null;
289
+ }
290
},
291
292
getUpdateCount(id) {
src/renderers/dom/shared/ReactDOMComponent.js
+2
-6
@@ -270,16 +270,12 @@ if (__DEV__) {
270
}
271
272
this._contentDebugID = contentDebugID;
273
- var text = '' + content;
274
-
275
- ReactInstrumentation.debugTool.onSetDisplayName(contentDebugID, '#text');
276
- ReactInstrumentation.debugTool.onSetParent(contentDebugID, debugID);
277
- ReactInstrumentation.debugTool.onSetText(contentDebugID, text);
278
-
273
if (hasExistingContent) {
274
ReactInstrumentation.debugTool.onBeforeUpdateComponent(contentDebugID, content);
275
ReactInstrumentation.debugTool.onUpdateComponent(contentDebugID);
276
} else {
277
+ ReactInstrumentation.debugTool.onInstantiateComponent(contentDebugID, content);
278
+ ReactInstrumentation.debugTool.onSetParent(contentDebugID, debugID);
279
ReactInstrumentation.debugTool.onBeforeMountComponent(contentDebugID, content);
280
ReactInstrumentation.debugTool.onMountComponent(contentDebugID);
281
ReactInstrumentation.debugTool.onSetChildren(debugID, [contentDebugID]);
src/renderers/dom/shared/ReactDOMTextComponent.js
-10
@@ -14,7 +14,6 @@
14
var DOMChildrenOperations = require('DOMChildrenOperations');
15
var DOMLazyTree = require('DOMLazyTree');
16
var ReactDOMComponentTree = require('ReactDOMComponentTree');
17
-var ReactInstrumentation = require('ReactInstrumentation');
17
18
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
19
var invariant = require('invariant');
@@ -67,8 +66,6 @@ Object.assign(ReactDOMTextComponent.prototype, {
66
context
67
) {
68
if (__DEV__) {
70
- ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText);
71
-
69
var parentInfo;
70
if (hostParent != null) {
71
parentInfo = hostParent._ancestorInfo;
@@ -142,13 +139,6 @@ Object.assign(ReactDOMTextComponent.prototype, {
139
commentNodes[1],
140
nextStringText
141
);
145
-
146
- if (__DEV__) {
147
- ReactInstrumentation.debugTool.onSetText(
148
- this._debugID,
149
- nextStringText
150
- );
151
- }
142
}
143
}
144
},
src/renderers/native/ReactNativeTextComponent.js
-11
@@ -11,7 +11,6 @@
11
12
'use strict';
13
14
-var ReactInstrumentation = require('ReactInstrumentation');
14
var ReactNativeComponentTree = require('ReactNativeComponentTree');
15
var ReactNativeTagHandles = require('ReactNativeTagHandles');
16
var UIManager = require('UIManager');
@@ -29,10 +28,6 @@ var ReactNativeTextComponent = function(text) {
28
Object.assign(ReactNativeTextComponent.prototype, {
29
30
mountComponent: function(transaction, hostParent, hostContainerInfo, context) {
32
- if (__DEV__) {
33
- ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText);
34
- }
35
-
31
// TODO: hostParent should have this context already. Stop abusing context.
32
invariant(
33
context.isInAParentText,
@@ -70,12 +65,6 @@ Object.assign(ReactNativeTextComponent.prototype, {
65
'RCTRawText',
66
{text: this._stringText}
67
);
73
- if (__DEV__) {
74
- ReactInstrumentation.debugTool.onSetText(
75
- this._debugID,
76
- nextStringText
77
- );
78
- }
68
}
69
}
70
},
src/renderers/shared/ReactDebugTool.js
+2
-10
@@ -283,26 +283,18 @@ var ReactDebugTool = {
283
onSetState() {
284
emitEvent('onSetState');
285
},
286
- onSetDisplayName(debugID, displayName) {
287
- checkDebugID(debugID);
288
- emitEvent('onSetDisplayName', debugID, displayName);
289
- },
286
onSetChildren(debugID, childDebugIDs) {
287
checkDebugID(debugID);
288
childDebugIDs.forEach(checkDebugID);
289
emitEvent('onSetChildren', debugID, childDebugIDs);
290
},
295
- onSetOwner(debugID, ownerDebugID) {
296
- checkDebugID(debugID);
297
- emitEvent('onSetOwner', debugID, ownerDebugID);
298
- },
291
onSetParent(debugID, parentDebugID) {
292
checkDebugID(debugID);
293
emitEvent('onSetParent', debugID, parentDebugID);
294
},
303
- onSetText(debugID, text) {
295
+ onInstantiateComponent(debugID, element) {
296
checkDebugID(debugID);
305
- emitEvent('onSetText', debugID, text);
297
+ emitEvent('onInstantiateComponent', debugID, element);
298
},
299
onMountRootComponent(debugID) {
300
checkDebugID(debugID);
src/renderers/shared/stack/reconciler/instantiateReactComponent.js
+1
-21
@@ -41,21 +41,6 @@ function getDeclarationErrorAddendum(owner) {
41
return '';
42
}
43
44
-function getDisplayName(instance) {
45
- var element = instance._currentElement;
46
- if (element == null) {
47
- return '#empty';
48
- } else if (typeof element === 'string' || typeof element === 'number') {
49
- return '#text';
50
- } else if (typeof element.type === 'string') {
51
- return element.type;
52
- } else if (instance.getName) {
53
- return instance.getName() || 'Unknown';
54
- } else {
55
- return element.type.displayName || element.type.name || 'Unknown';
56
- }
57
-}
58
-
44
/**
45
* Check if the type reference is a known internal type. I.e. not a user
46
* provided composite type.
@@ -144,12 +129,7 @@ function instantiateReactComponent(node, shouldHaveDebugID) {
129
if (shouldHaveDebugID) {
130
var debugID = nextDebugID++;
131
instance._debugID = debugID;
147
- var displayName = getDisplayName(instance);
148
- ReactInstrumentation.debugTool.onSetDisplayName(debugID, displayName);
149
- var owner = node && node._owner;
150
- if (owner) {
151
- ReactInstrumentation.debugTool.onSetOwner(debugID, owner._debugID);
152
- }
132
+ ReactInstrumentation.debugTool.onInstantiateComponent(debugID, node);
133
} else {
134
instance._debugID = 0;
135
}
src/test/ReactTestUtils.js
+2
-2
@@ -384,6 +384,7 @@ var NoopInternalComponent = function(element) {
384
this._renderedOutput = element;
385
this._currentElement = element;
386
this._debugID = nextDebugID++;
387
+ ReactInstrumentation.debugTool.onInstantiateComponent(this._debugID, element);
388
};
389
390
NoopInternalComponent.prototype = {
@@ -412,8 +413,7 @@ var ShallowComponentWrapper = function(element) {
413
// TODO: Consolidate with instantiateReactComponent
414
if (__DEV__) {
415
this._debugID = nextDebugID++;
415
- var displayName = element.type.displayName || element.type.name || 'Unknown';
416
- ReactInstrumentation.debugTool.onSetDisplayName(this._debugID, displayName);
416
+ ReactInstrumentation.debugTool.onInstantiateComponent(this._debugID, element);
417
}
418
419
this.construct(element);