@samitouri / QOS-React-2 / commits / 03f4ba260b

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