diff --git a/src/isomorphic/ReactDebugTool.js b/src/isomorphic/ReactDebugTool.js new file mode 100644 index 000000000000..2435a613f400 --- /dev/null +++ b/src/isomorphic/ReactDebugTool.js @@ -0,0 +1,65 @@ +/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDebugTool + */ + +'use strict'; + +var warning = require('warning'); + +var eventHandlers = []; +var handlerDoesThrowForEvent = {}; + +function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) { + if (__DEV__) { + eventHandlers.forEach(function(handler) { + try { + if (handler[handlerFunctionName]) { + handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5); + } + } catch (e) { + warning( + !handlerDoesThrowForEvent[handlerFunctionName], + 'exception thrown by devtool while handling %s: %s', + handlerFunctionName, + e.message + ); + handlerDoesThrowForEvent[handlerFunctionName] = true; + } + }); + } +} + +var ReactDebugTool = { + addDevtool(devtool) { + eventHandlers.push(devtool); + }, + removeDevtool(devtool) { + for (var i = 0; i < eventHandlers.length; i++) { + if (eventHandlers[i] === devtool) { + eventHandlers.splice(i, 1); + i--; + } + } + }, + onMountRootComponent(internalInstance) { + emitEvent('onMountRootComponent', internalInstance); + }, + onMountComponent(internalInstance) { + emitEvent('onMountComponent', internalInstance); + }, + onUpdateComponent(internalInstance) { + emitEvent('onUpdateComponent', internalInstance); + }, + onUnmountComponent(internalInstance) { + emitEvent('onUnmountComponent', internalInstance); + }, +}; + +module.exports = ReactDebugTool; diff --git a/src/isomorphic/ReactInstrumentation.js b/src/isomorphic/ReactInstrumentation.js new file mode 100644 index 000000000000..066da6aaae82 --- /dev/null +++ b/src/isomorphic/ReactInstrumentation.js @@ -0,0 +1,16 @@ +/** + * Copyright 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactInstrumentation + */ + +'use strict'; + +var ReactDebugTool = require('ReactDebugTool'); + +module.exports = {debugTool: ReactDebugTool}; diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js index ea62047b0aba..4b11559670cd 100644 --- a/src/renderers/dom/client/ReactMount.js +++ b/src/renderers/dom/client/ReactMount.js @@ -20,6 +20,7 @@ var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactElement = require('ReactElement'); var ReactFeatureFlags = require('ReactFeatureFlags'); +var ReactInstrumentation = require('ReactInstrumentation'); var ReactMarkupChecksum = require('ReactMarkupChecksum'); var ReactPerf = require('ReactPerf'); var ReactReconciler = require('ReactReconciler'); @@ -347,6 +348,10 @@ var ReactMount = { var wrapperID = componentInstance._instance.rootID; instancesByReactRootID[wrapperID] = componentInstance; + if (__DEV__) { + ReactInstrumentation.debugTool.onMountRootComponent(componentInstance); + } + return componentInstance; }, diff --git a/src/renderers/shared/reconciler/ReactReconciler.js b/src/renderers/shared/reconciler/ReactReconciler.js index 507d351612a9..ae7806e4fc0e 100644 --- a/src/renderers/shared/reconciler/ReactReconciler.js +++ b/src/renderers/shared/reconciler/ReactReconciler.js @@ -12,6 +12,7 @@ 'use strict'; var ReactRef = require('ReactRef'); +var ReactInstrumentation = require('ReactInstrumentation'); /** * Helper to call ReactRef.attachRefs with this composite component, split out @@ -51,6 +52,9 @@ var ReactReconciler = { internalInstance._currentElement.ref != null) { transaction.getReactMountReady().enqueue(attachRefs, internalInstance); } + if (__DEV__) { + ReactInstrumentation.debugTool.onMountComponent(internalInstance); + } return markup; }, @@ -70,7 +74,10 @@ var ReactReconciler = { */ unmountComponent: function(internalInstance, safely) { ReactRef.detachRefs(internalInstance, internalInstance._currentElement); - return internalInstance.unmountComponent(safely); + internalInstance.unmountComponent(safely); + if (__DEV__) { + ReactInstrumentation.debugTool.onUnmountComponent(internalInstance); + } }, /** @@ -119,6 +126,10 @@ var ReactReconciler = { internalInstance._currentElement.ref != null) { transaction.getReactMountReady().enqueue(attachRefs, internalInstance); } + + if (__DEV__) { + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance); + } }, /** @@ -133,6 +144,9 @@ var ReactReconciler = { transaction ) { internalInstance.performUpdateIfNecessary(transaction); + if (__DEV__) { + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance); + } }, };