Add ReactInstrumentation
This adds `ReactInstrumentation` for the isomorphic package that uses the same approach as `ReactDOMInstrumentation`. Currently it is gated behind `__DEV__` but we will likely change this later to a runtime flag determined by whether there are any active listeners. The first few events we add here should be sufficient for React DevTools, as determined by the `hook.emit()` calls in https://github.com/facebook/react-devtools/blob/d90c43201617d5aef378669da926d79515b6a811/backend/attachRenderer.js. These events will also be useful for reconstructing the parent tree in the ReactPerf rewrite in #6046.
Dan Abramov committed
Feb 18, 2016 at 22:52 UTC
3863330524d99b5ebedbfa65bc09fa46ae7fa8a6
4 files changed
+101
-1
src/isomorphic/ReactDebugTool.js
new
+65
@@ -0,0 +1,65 @@
1
+/**
2
+ * Copyright 2016-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactDebugTool
10
+ */
11
+
12
+'use strict';
13
+
14
+var warning = require('warning');
15
+
16
+var eventHandlers = [];
17
+var handlerDoesThrowForEvent = {};
18
+
19
+function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) {
20
+ if (__DEV__) {
21
+ eventHandlers.forEach(function(handler) {
22
+ try {
23
+ if (handler[handlerFunctionName]) {
24
+ handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5);
25
+ }
26
+ } catch (e) {
27
+ warning(
28
+ !handlerDoesThrowForEvent[handlerFunctionName],
29
+ 'exception thrown by devtool while handling %s: %s',
30
+ handlerFunctionName,
31
+ e.message
32
+ );
33
+ handlerDoesThrowForEvent[handlerFunctionName] = true;
34
+ }
35
+ });
36
+ }
37
+}
38
+
39
+var ReactDebugTool = {
40
+ addDevtool(devtool) {
41
+ eventHandlers.push(devtool);
42
+ },
43
+ removeDevtool(devtool) {
44
+ for (var i = 0; i < eventHandlers.length; i++) {
45
+ if (eventHandlers[i] === devtool) {
46
+ eventHandlers.splice(i, 1);
47
+ i--;
48
+ }
49
+ }
50
+ },
51
+ onMountRootComponent(internalInstance) {
52
+ emitEvent('onMountRootComponent', internalInstance);
53
+ },
54
+ onMountComponent(internalInstance) {
55
+ emitEvent('onMountComponent', internalInstance);
56
+ },
57
+ onUpdateComponent(internalInstance) {
58
+ emitEvent('onUpdateComponent', internalInstance);
59
+ },
60
+ onUnmountComponent(internalInstance) {
61
+ emitEvent('onUnmountComponent', internalInstance);
62
+ },
63
+};
64
+
65
+module.exports = ReactDebugTool;
src/isomorphic/ReactInstrumentation.js
new
+16
@@ -0,0 +1,16 @@
1
+/**
2
+ * Copyright 2016-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactInstrumentation
10
+ */
11
+
12
+'use strict';
13
+
14
+var ReactDebugTool = require('ReactDebugTool');
15
+
16
+module.exports = {debugTool: ReactDebugTool};
src/renderers/dom/client/ReactMount.js
+5
@@ -20,6 +20,7 @@ var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
20
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
21
var ReactElement = require('ReactElement');
22
var ReactFeatureFlags = require('ReactFeatureFlags');
23
+var ReactInstrumentation = require('ReactInstrumentation');
24
var ReactMarkupChecksum = require('ReactMarkupChecksum');
25
var ReactPerf = require('ReactPerf');
26
var ReactReconciler = require('ReactReconciler');
@@ -347,6 +348,10 @@ var ReactMount = {
348
var wrapperID = componentInstance._instance.rootID;
349
instancesByReactRootID[wrapperID] = componentInstance;
350
351
+ if (__DEV__) {
352
+ ReactInstrumentation.debugTool.onMountRootComponent(componentInstance);
353
+ }
354
+
355
return componentInstance;
356
},
357
src/renderers/shared/reconciler/ReactReconciler.js
+15
-1
@@ -12,6 +12,7 @@
12
'use strict';
13
14
var ReactRef = require('ReactRef');
15
+var ReactInstrumentation = require('ReactInstrumentation');
16
17
/**
18
* Helper to call ReactRef.attachRefs with this composite component, split out
@@ -51,6 +52,9 @@ var ReactReconciler = {
52
internalInstance._currentElement.ref != null) {
53
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
54
}
55
+ if (__DEV__) {
56
+ ReactInstrumentation.debugTool.onMountComponent(internalInstance);
57
+ }
58
return markup;
59
},
60
@@ -70,7 +74,10 @@ var ReactReconciler = {
74
*/
75
unmountComponent: function(internalInstance, safely) {
76
ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
73
- return internalInstance.unmountComponent(safely);
77
+ internalInstance.unmountComponent(safely);
78
+ if (__DEV__) {
79
+ ReactInstrumentation.debugTool.onUnmountComponent(internalInstance);
80
+ }
81
},
82
83
/**
@@ -119,6 +126,10 @@ var ReactReconciler = {
126
internalInstance._currentElement.ref != null) {
127
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
128
}
129
+
130
+ if (__DEV__) {
131
+ ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
132
+ }
133
},
134
135
/**
@@ -133,6 +144,9 @@ var ReactReconciler = {
144
transaction
145
) {
146
internalInstance.performUpdateIfNecessary(transaction);
147
+ if (__DEV__) {
148
+ ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
149
+ }
150
},
151
152
};