Track source more generically in ReactComponentTreeDevtool (#6765)
Being able to get the source for your parent components seems useful, and ReactComponentTreeDevtool is best poised to be able to do that. I'm also not sure it makes sense to have separate DOM-specific `onMountDOMComponent` and `onUpdateDOMComponent` events, so I removed them for now. Even if we want them, their timing seemed sort of arbitrary. I also made it so DOM devtools can listen to non-DOM events too. Willing to change that if people think it's ugly though.
Ben Alpert committed
May 14, 2016 at 12:12 UTC
03f4ba260b7cfe78ea15b34d8169e42fea2c874e
7 files changed
+65
-29
src/isomorphic/ReactDebugTool.js
+8
@@ -244,10 +244,18 @@ var ReactDebugTool = {
244
checkDebugID(debugID);
245
emitEvent('onMountRootComponent', debugID);
246
},
247
+ onBeforeMountComponent(debugID, element) {
248
+ checkDebugID(debugID);
249
+ emitEvent('onBeforeMountComponent', debugID, element);
250
+ },
251
onMountComponent(debugID) {
252
checkDebugID(debugID);
253
emitEvent('onMountComponent', debugID);
254
},
255
+ onBeforeUpdateComponent(debugID, element) {
256
+ checkDebugID(debugID);
257
+ emitEvent('onBeforeUpdateComponent', debugID, element);
258
+ },
259
onUpdateComponent(debugID) {
260
checkDebugID(debugID);
261
emitEvent('onUpdateComponent', debugID);
src/isomorphic/devtools/ReactComponentTreeDevtool.js
+16
@@ -19,6 +19,7 @@ var rootIDs = [];
19
function updateTree(id, update) {
20
if (!tree[id]) {
21
tree[id] = {
22
+ element: null,
23
parentID: null,
24
ownerID: null,
25
text: null,
@@ -88,6 +89,14 @@ var ReactComponentTreeDevtool = {
89
updateTree(id, item => item.text = text);
90
},
91
92
+ onBeforeMountComponent(id, element) {
93
+ updateTree(id, item => item.element = element);
94
+ },
95
+
96
+ onBeforeUpdateComponent(id, element) {
97
+ updateTree(id, item => item.element = element);
98
+ },
99
+
100
onMountComponent(id) {
101
updateTree(id, item => item.isMounted = true);
102
},
@@ -141,6 +150,13 @@ var ReactComponentTreeDevtool = {
150
return item ? item.parentID : null;
151
},
152
153
+ getSource(id) {
154
+ var item = tree[id];
155
+ var element = item ? item.element : null;
156
+ var source = element != null ? element._source : null;
157
+ return source;
158
+ },
159
+
160
getText(id) {
161
var item = tree[id];
162
return item ? item.text : null;
src/renderers/dom/shared/ReactDOMComponent.js
-9
@@ -29,7 +29,6 @@ var ReactDOMButton = require('ReactDOMButton');
29
var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
30
var ReactDOMComponentTree = require('ReactDOMComponentTree');
31
var ReactDOMInput = require('ReactDOMInput');
32
-var ReactDOMInstrumentation = require('ReactDOMInstrumentation');
32
var ReactDOMOption = require('ReactDOMOption');
33
var ReactDOMSelect = require('ReactDOMSelect');
34
var ReactDOMTextarea = require('ReactDOMTextarea');
@@ -579,10 +578,6 @@ ReactDOMComponent.Mixin = {
578
validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
579
}
580
582
- if (__DEV__) {
583
- ReactDOMInstrumentation.debugTool.onMountDOMComponent(this._debugID, this._currentElement);
584
- }
585
-
581
var mountImage;
582
if (transaction.useCreateElement) {
583
var ownerDocument = hostContainerInfo._ownerDocument;
@@ -858,10 +853,6 @@ ReactDOMComponent.Mixin = {
853
context
854
);
855
861
- if (__DEV__) {
862
- ReactDOMInstrumentation.debugTool.onUpdateDOMComponent(this._debugID, this._currentElement);
863
- }
864
-
856
if (this._tag === 'select') {
857
// <select> value update needs to occur after <option> children
858
// reconciliation
src/renderers/dom/shared/ReactDOMDebugTool.js
+3
-6
@@ -12,6 +12,7 @@
12
'use strict';
13
14
var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool');
15
+var ReactDebugTool = require('ReactDebugTool');
16
17
var warning = require('warning');
18
@@ -40,9 +41,11 @@ function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) {
41
42
var ReactDOMDebugTool = {
43
addDevtool(devtool) {
44
+ ReactDebugTool.addDevtool(devtool);
45
eventHandlers.push(devtool);
46
},
47
removeDevtool(devtool) {
48
+ ReactDebugTool.removeDevtool(devtool);
49
for (var i = 0; i < eventHandlers.length; i++) {
50
if (eventHandlers[i] === devtool) {
51
eventHandlers.splice(i, 1);
@@ -62,12 +65,6 @@ var ReactDOMDebugTool = {
65
onTestEvent() {
66
emitEvent('onTestEvent');
67
},
65
- onMountDOMComponent(debugID, element) {
66
- emitEvent('onMountDOMComponent', debugID, element);
67
- },
68
- onUpdateDOMComponent(debugID, element) {
69
- emitEvent('onMountDOMComponent', debugID, element);
70
- },
68
};
69
70
ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool);
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+16
-3
@@ -1315,8 +1315,17 @@ describe('ReactDOMComponent', function() {
1315
ReactDOMServer.renderToString(<div class="paladin"/>);
1316
ReactDOMServer.renderToString(<input type="text" onclick="1"/>);
1317
expect(console.error.argsForCall.length).toBe(2);
1318
- expect(console.error.argsForCall[0][0]).toMatch(/.*className.*\(.*:\d+\)/);
1319
- expect(console.error.argsForCall[1][0]).toMatch(/.*onClick.*\(.*:\d+\)/);
1318
+ expect(
1319
+ console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1320
+ ).toBe(
1321
+ 'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1322
+ );
1323
+ expect(
1324
+ console.error.argsForCall[1][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1325
+ ).toBe(
1326
+ 'Warning: Unknown event handler property onclick. Did you mean ' +
1327
+ '`onClick`? (**:*)'
1328
+ );
1329
});
1330
1331
it('gives source code refs for unknown prop warning for update render', function() {
@@ -1328,7 +1337,11 @@ describe('ReactDOMComponent', function() {
1337
1338
ReactDOMServer.renderToString(<div class="paladin" />, container);
1339
expect(console.error.argsForCall.length).toBe(1);
1331
- expect(console.error.argsForCall[0][0]).toMatch(/.*className.*\(.*:\d+\)/);
1340
+ expect(
1341
+ console.error.argsForCall[0][0].replace(/\(.+?:\d+\)/g, '(**:*)')
1342
+ ).toBe(
1343
+ 'Warning: Unknown DOM property class. Did you mean className? (**:*)'
1344
+ );
1345
});
1346
1347
it('gives source code refs for unknown prop warning for exact elements ', function() {
src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js
+14
-11
@@ -13,11 +13,12 @@
13
14
var DOMProperty = require('DOMProperty');
15
var EventPluginRegistry = require('EventPluginRegistry');
16
+var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool');
17
18
var warning = require('warning');
19
20
if (__DEV__) {
20
- var cachedSource;
21
+ var lastDebugID;
22
var reactProps = {
23
children: true,
24
dangerouslySetInnerHTML: true,
@@ -47,6 +48,10 @@ if (__DEV__) {
48
null
49
);
50
51
+ var source = ReactComponentTreeDevtool.getSource(lastDebugID);
52
+ var formattedSource = source ?
53
+ `(${source.fileName.replace(/^.*[\\\/]/, '')}:${source.lineNumber})` : '';
54
+
55
// For now, only warn when we have a suggested correction. This prevents
56
// logging too much when using transferPropsTo.
57
warning(
@@ -54,7 +59,7 @@ if (__DEV__) {
59
'Unknown DOM property %s. Did you mean %s? %s',
60
name,
61
standardName,
57
- formatSource(cachedSource)
62
+ formattedSource
63
);
64
65
var registrationName = (
@@ -70,14 +75,10 @@ if (__DEV__) {
75
'Unknown event handler property %s. Did you mean `%s`? %s',
76
name,
77
registrationName,
73
- formatSource(cachedSource)
78
+ formattedSource
79
);
80
};
81
77
- var formatSource = function(source) {
78
- return source ? `(${source.fileName.replace(/^.*[\\\/]/, '')}:${source.lineNumber})` : '';
79
- };
80
-
82
}
83
84
var ReactDOMUnknownPropertyDevtool = {
@@ -90,11 +91,13 @@ var ReactDOMUnknownPropertyDevtool = {
91
onDeleteValueForProperty(node, name) {
92
warnUnknownProperty(name);
93
},
93
- onMountDOMComponent(debugID, element) {
94
- cachedSource = element ? element._source : null;
94
+ onBeforeMountComponent(debugID, element) {
95
+ // TODO: This currently assumes that properties are all set before recursing
96
+ // and mounting children, which needn't be the case in the future.
97
+ lastDebugID = debugID;
98
},
96
- onUpdateDOMComponent(debugID, element) {
97
- cachedSource = element ? element._source : null;
99
+ onBeforeUpdateComponent(debugID, element) {
100
+ lastDebugID = debugID;
101
},
102
};
103
src/renderers/shared/stack/reconciler/ReactReconciler.js
+8
@@ -50,6 +50,10 @@ var ReactReconciler = {
50
internalInstance._debugID,
51
'mountComponent'
52
);
53
+ ReactInstrumentation.debugTool.onBeforeMountComponent(
54
+ internalInstance._debugID,
55
+ internalInstance._currentElement
56
+ );
57
}
58
}
59
var markup = internalInstance.mountComponent(
@@ -150,6 +154,10 @@ var ReactReconciler = {
154
internalInstance._debugID,
155
'receiveComponent'
156
);
157
+ ReactInstrumentation.debugTool.onBeforeUpdateComponent(
158
+ internalInstance._debugID,
159
+ internalInstance._currentElement
160
+ );
161
}
162
}
163