mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #6549 from gaearon/instrumentation-new
Provide info about component tree to devtools
This commit is contained in:
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* 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 ReactDebugInstanceMap
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var warning = require('warning');
|
||||
|
||||
function checkValidInstance(internalInstance) {
|
||||
if (!internalInstance) {
|
||||
warning(
|
||||
false,
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'Instead of an internal instance, received %s. ' +
|
||||
'Please report this as a bug in React.',
|
||||
internalInstance
|
||||
);
|
||||
return false;
|
||||
}
|
||||
var isValid = typeof internalInstance.mountComponent === 'function';
|
||||
warning(
|
||||
isValid,
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'Instead of an internal instance, received an object with the following ' +
|
||||
'keys: %s. Please report this as a bug in React.',
|
||||
Object.keys(internalInstance).join(', ')
|
||||
);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
var idCounter = 1;
|
||||
var instancesByIDs = {};
|
||||
var instancesToIDs;
|
||||
|
||||
function getIDForInstance(internalInstance) {
|
||||
if (!instancesToIDs) {
|
||||
instancesToIDs = new WeakMap();
|
||||
}
|
||||
if (instancesToIDs.has(internalInstance)) {
|
||||
return instancesToIDs.get(internalInstance);
|
||||
} else {
|
||||
var instanceID = (idCounter++).toString();
|
||||
instancesToIDs.set(internalInstance, instanceID);
|
||||
return instanceID;
|
||||
}
|
||||
}
|
||||
|
||||
function getInstanceByID(instanceID) {
|
||||
return instancesByIDs[instanceID] || null;
|
||||
}
|
||||
|
||||
function isRegisteredInstance(internalInstance) {
|
||||
var instanceID = getIDForInstance(internalInstance);
|
||||
if (instanceID) {
|
||||
return instancesByIDs.hasOwnProperty(instanceID);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function registerInstance(internalInstance) {
|
||||
var instanceID = getIDForInstance(internalInstance);
|
||||
if (instanceID) {
|
||||
instancesByIDs[instanceID] = internalInstance;
|
||||
}
|
||||
}
|
||||
|
||||
function unregisterInstance(internalInstance) {
|
||||
var instanceID = getIDForInstance(internalInstance);
|
||||
if (instanceID) {
|
||||
delete instancesByIDs[instanceID];
|
||||
}
|
||||
}
|
||||
|
||||
var ReactDebugInstanceMap = {
|
||||
getIDForInstance(internalInstance) {
|
||||
if (!checkValidInstance(internalInstance)) {
|
||||
return null;
|
||||
}
|
||||
return getIDForInstance(internalInstance);
|
||||
},
|
||||
getInstanceByID(instanceID) {
|
||||
return getInstanceByID(instanceID);
|
||||
},
|
||||
isRegisteredInstance(internalInstance) {
|
||||
if (!checkValidInstance(internalInstance)) {
|
||||
return false;
|
||||
}
|
||||
return isRegisteredInstance(internalInstance);
|
||||
},
|
||||
registerInstance(internalInstance) {
|
||||
if (!checkValidInstance(internalInstance)) {
|
||||
return;
|
||||
}
|
||||
warning(
|
||||
!isRegisteredInstance(internalInstance),
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'A registered instance should not be registered again. ' +
|
||||
'Please report this as a bug in React.'
|
||||
);
|
||||
registerInstance(internalInstance);
|
||||
},
|
||||
unregisterInstance(internalInstance) {
|
||||
if (!checkValidInstance(internalInstance)) {
|
||||
return;
|
||||
}
|
||||
warning(
|
||||
isRegisteredInstance(internalInstance),
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'An unregistered instance should not be unregistered again. ' +
|
||||
'Please report this as a bug in React.'
|
||||
);
|
||||
unregisterInstance(internalInstance);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactDebugInstanceMap;
|
||||
@@ -58,17 +58,29 @@ var ReactDebugTool = {
|
||||
onSetState() {
|
||||
emitEvent('onSetState');
|
||||
},
|
||||
onMountRootComponent(internalInstance) {
|
||||
emitEvent('onMountRootComponent', internalInstance);
|
||||
onSetDisplayName(debugID, displayName) {
|
||||
emitEvent('onSetDisplayName', debugID, displayName);
|
||||
},
|
||||
onMountComponent(internalInstance) {
|
||||
emitEvent('onMountComponent', internalInstance);
|
||||
onSetChildren(debugID, childDebugIDs) {
|
||||
emitEvent('onSetChildren', debugID, childDebugIDs);
|
||||
},
|
||||
onUpdateComponent(internalInstance) {
|
||||
emitEvent('onUpdateComponent', internalInstance);
|
||||
onSetOwner(debugID, ownerDebugID) {
|
||||
emitEvent('onSetOwner', debugID, ownerDebugID);
|
||||
},
|
||||
onUnmountComponent(internalInstance) {
|
||||
emitEvent('onUnmountComponent', internalInstance);
|
||||
onSetText(debugID, text) {
|
||||
emitEvent('onSetText', debugID, text);
|
||||
},
|
||||
onMountRootComponent(debugID) {
|
||||
emitEvent('onMountRootComponent', debugID);
|
||||
},
|
||||
onMountComponent(debugID) {
|
||||
emitEvent('onMountComponent', debugID);
|
||||
},
|
||||
onUpdateComponent(debugID) {
|
||||
emitEvent('onUpdateComponent', debugID);
|
||||
},
|
||||
onUnmountComponent(debugID) {
|
||||
emitEvent('onUnmountComponent', debugID);
|
||||
},
|
||||
onTestEvent() {
|
||||
emitEvent('onTestEvent');
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('ReactDebugInstanceMap', function() {
|
||||
var React;
|
||||
var ReactDebugInstanceMap;
|
||||
var ReactDOM;
|
||||
|
||||
beforeEach(function() {
|
||||
jest.resetModuleRegistry();
|
||||
React = require('React');
|
||||
ReactDebugInstanceMap = require('ReactDebugInstanceMap');
|
||||
ReactDOM = require('ReactDOM');
|
||||
});
|
||||
|
||||
function createStubInstance() {
|
||||
return { mountComponent: () => {} };
|
||||
}
|
||||
|
||||
it('should register and unregister instances', function() {
|
||||
var inst1 = createStubInstance();
|
||||
var inst2 = createStubInstance();
|
||||
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst1);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(true);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst1);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false);
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
|
||||
});
|
||||
|
||||
it('should assign stable IDs', function() {
|
||||
var inst1 = createStubInstance();
|
||||
var inst2 = createStubInstance();
|
||||
|
||||
var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1);
|
||||
var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2);
|
||||
expect(typeof inst1ID).toBe('string');
|
||||
expect(typeof inst2ID).toBe('string');
|
||||
expect(inst1ID).not.toBe(inst2ID);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst1);
|
||||
ReactDebugInstanceMap.registerInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID);
|
||||
expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst1);
|
||||
ReactDebugInstanceMap.unregisterInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID);
|
||||
expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID);
|
||||
});
|
||||
|
||||
it('should retrieve registered instance by its ID', function() {
|
||||
var inst1 = createStubInstance();
|
||||
var inst2 = createStubInstance();
|
||||
|
||||
var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1);
|
||||
var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst1);
|
||||
ReactDebugInstanceMap.registerInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(inst1);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(inst2);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst1);
|
||||
ReactDebugInstanceMap.unregisterInstance(inst2);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null);
|
||||
expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null);
|
||||
});
|
||||
|
||||
it('should warn when registering an instance twice', function() {
|
||||
spyOn(console, 'error');
|
||||
|
||||
var inst = createStubInstance();
|
||||
ReactDebugInstanceMap.registerInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(0);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(1);
|
||||
expect(console.error.argsForCall[0][0]).toContain(
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'A registered instance should not be registered again. ' +
|
||||
'Please report this as a bug in React.'
|
||||
);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst);
|
||||
ReactDebugInstanceMap.registerInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should warn when unregistering an instance twice', function() {
|
||||
spyOn(console, 'error');
|
||||
var inst = createStubInstance();
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(1);
|
||||
expect(console.error.argsForCall[0][0]).toContain(
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'An unregistered instance should not be unregistered again. ' +
|
||||
'Please report this as a bug in React.'
|
||||
);
|
||||
|
||||
ReactDebugInstanceMap.registerInstance(inst);
|
||||
ReactDebugInstanceMap.unregisterInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(1);
|
||||
|
||||
ReactDebugInstanceMap.unregisterInstance(inst);
|
||||
expect(console.error.argsForCall.length).toBe(2);
|
||||
expect(console.error.argsForCall[1][0]).toContain(
|
||||
'There is an internal error in the React developer tools integration. ' +
|
||||
'An unregistered instance should not be unregistered again. ' +
|
||||
'Please report this as a bug in React.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn about anything than is not an internal instance', function() {
|
||||
class Foo extends React.Component {
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
spyOn(console, 'error');
|
||||
var warningCount = 0;
|
||||
var div = document.createElement('div');
|
||||
var publicInst = ReactDOM.render(<Foo />, div);
|
||||
|
||||
[false, null, undefined, {}, div, publicInst].forEach(falsyValue => {
|
||||
ReactDebugInstanceMap.registerInstance(falsyValue);
|
||||
warningCount++;
|
||||
expect(ReactDebugInstanceMap.getIDForInstance(falsyValue)).toBe(null);
|
||||
warningCount++;
|
||||
expect(ReactDebugInstanceMap.isRegisteredInstance(falsyValue)).toBe(false);
|
||||
warningCount++;
|
||||
ReactDebugInstanceMap.unregisterInstance(falsyValue);
|
||||
warningCount++;
|
||||
});
|
||||
|
||||
expect(console.error.argsForCall.length).toBe(warningCount);
|
||||
for (var i = 0; i < warningCount.length; i++) {
|
||||
// Ideally we could check for the more detailed error message here
|
||||
// but it depends on the input type and is meant for internal bugs
|
||||
// anyway so I don't think it's worth complicating the test with it.
|
||||
expect(console.error.argsForCall[i][0]).toContain(
|
||||
'There is an internal error in the React developer tools integration.'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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 ReactComponentTreeDevtool
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var tree = {};
|
||||
var rootIDs = [];
|
||||
|
||||
function updateTree(id, update) {
|
||||
if (!tree[id]) {
|
||||
tree[id] = {
|
||||
parentID: null,
|
||||
ownerID: null,
|
||||
text: null,
|
||||
childIDs: [],
|
||||
displayName: 'Unknown',
|
||||
isMounted: false,
|
||||
};
|
||||
}
|
||||
update(tree[id]);
|
||||
}
|
||||
|
||||
function purgeDeep(id) {
|
||||
var item = tree[id];
|
||||
if (item) {
|
||||
var {childIDs} = item;
|
||||
delete tree[id];
|
||||
childIDs.forEach(purgeDeep);
|
||||
}
|
||||
}
|
||||
|
||||
var ReactComponentTreeDevtool = {
|
||||
onSetDisplayName(id, displayName) {
|
||||
updateTree(id, item => item.displayName = displayName);
|
||||
},
|
||||
|
||||
onSetChildren(id, nextChildIDs) {
|
||||
updateTree(id, item => {
|
||||
var prevChildIDs = item.childIDs;
|
||||
item.childIDs = nextChildIDs;
|
||||
|
||||
nextChildIDs.forEach(nextChildID => {
|
||||
var nextChild = tree[nextChildID];
|
||||
invariant(
|
||||
nextChild,
|
||||
'Expected devtool events to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
);
|
||||
invariant(
|
||||
nextChild.displayName != null,
|
||||
'Expected onSetDisplayName() to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
);
|
||||
invariant(
|
||||
nextChild.childIDs != null || nextChild.text != null,
|
||||
'Expected onSetChildren() or onSetText() to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
);
|
||||
invariant(
|
||||
nextChild.isMounted,
|
||||
'Expected onMountComponent() to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
);
|
||||
|
||||
if (prevChildIDs.indexOf(nextChildID) === -1) {
|
||||
nextChild.parentID = id;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
onSetOwner(id, ownerID) {
|
||||
updateTree(id, item => item.ownerID = ownerID);
|
||||
},
|
||||
|
||||
onSetText(id, text) {
|
||||
updateTree(id, item => item.text = text);
|
||||
},
|
||||
|
||||
onMountComponent(id) {
|
||||
updateTree(id, item => item.isMounted = true);
|
||||
},
|
||||
|
||||
onMountRootComponent(id) {
|
||||
rootIDs.push(id);
|
||||
},
|
||||
|
||||
onUnmountComponent(id) {
|
||||
updateTree(id, item => item.isMounted = false);
|
||||
rootIDs = rootIDs.filter(rootID => rootID !== id);
|
||||
},
|
||||
|
||||
purgeUnmountedComponents() {
|
||||
Object.keys(tree)
|
||||
.filter(id => !tree[id].isMounted)
|
||||
.forEach(purgeDeep);
|
||||
},
|
||||
|
||||
isMounted(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.isMounted : false;
|
||||
},
|
||||
|
||||
getChildIDs(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.childIDs : [];
|
||||
},
|
||||
|
||||
getDisplayName(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.displayName : 'Unknown';
|
||||
},
|
||||
|
||||
getOwnerID(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.ownerID : null;
|
||||
},
|
||||
|
||||
getParentID(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.parentID : null;
|
||||
},
|
||||
|
||||
getText(id) {
|
||||
var item = tree[id];
|
||||
return item ? item.text : null;
|
||||
},
|
||||
|
||||
getRootIDs() {
|
||||
return rootIDs;
|
||||
},
|
||||
|
||||
getRegisteredIDs() {
|
||||
return Object.keys(tree);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactComponentTreeDevtool;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -333,6 +333,12 @@ var ReactMount = {
|
||||
ReactBrowserEventEmitter.ensureScrollValueMonitoring();
|
||||
var componentInstance = instantiateReactComponent(nextElement);
|
||||
|
||||
if (__DEV__) {
|
||||
// Mute future events from the top level wrapper.
|
||||
// It is an implementation detail that devtools should not know about.
|
||||
componentInstance._debugID = 0;
|
||||
}
|
||||
|
||||
// The initial render is synchronous but any updates that happen during
|
||||
// rendering, in componentWillMount or componentDidMount, will be batched
|
||||
// according to the current batching strategy.
|
||||
@@ -349,7 +355,10 @@ var ReactMount = {
|
||||
instancesByReactRootID[wrapperID] = componentInstance;
|
||||
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onMountRootComponent(componentInstance);
|
||||
// The instance here is TopLevelWrapper so we report mount for its child.
|
||||
ReactInstrumentation.debugTool.onMountRootComponent(
|
||||
componentInstance._renderedComponent._debugID
|
||||
);
|
||||
}
|
||||
|
||||
return componentInstance;
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
|
||||
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactMarkupChecksum = require('ReactMarkupChecksum');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactServerBatchingStrategy = require('ReactServerBatchingStrategy');
|
||||
var ReactServerRenderingTransaction =
|
||||
require('ReactServerRenderingTransaction');
|
||||
@@ -36,12 +38,18 @@ function renderToStringImpl(element, makeStaticMarkup) {
|
||||
|
||||
return transaction.perform(function() {
|
||||
var componentInstance = instantiateReactComponent(element);
|
||||
var markup = componentInstance.mountComponent(
|
||||
var markup = ReactReconciler.mountComponent(
|
||||
componentInstance,
|
||||
transaction,
|
||||
null,
|
||||
ReactDOMContainerInfo(),
|
||||
emptyObject
|
||||
);
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onUnmountComponent(
|
||||
componentInstance._debugID
|
||||
);
|
||||
}
|
||||
if (!makeStaticMarkup) {
|
||||
markup = ReactMarkupChecksum.addChecksumToMarkup(markup);
|
||||
}
|
||||
|
||||
@@ -32,9 +32,11 @@ var ReactDOMInput = require('ReactDOMInput');
|
||||
var ReactDOMOption = require('ReactDOMOption');
|
||||
var ReactDOMSelect = require('ReactDOMSelect');
|
||||
var ReactDOMTextarea = require('ReactDOMTextarea');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactMultiChild = require('ReactMultiChild');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
|
||||
var invariant = require('invariant');
|
||||
var isEventSupported = require('isEventSupported');
|
||||
@@ -245,6 +247,19 @@ function optionPostMount() {
|
||||
ReactDOMOption.postMountWrapper(inst);
|
||||
}
|
||||
|
||||
var setContentChildForInstrumentation = emptyFunction;
|
||||
if (__DEV__) {
|
||||
setContentChildForInstrumentation = function(contentToUse) {
|
||||
var debugID = this._debugID;
|
||||
var contentDebugID = debugID + '#text';
|
||||
this._contentDebugID = contentDebugID;
|
||||
ReactInstrumentation.debugTool.onSetDisplayName(contentDebugID, '#text');
|
||||
ReactInstrumentation.debugTool.onSetText(contentDebugID, '' + contentToUse);
|
||||
ReactInstrumentation.debugTool.onMountComponent(contentDebugID);
|
||||
ReactInstrumentation.debugTool.onSetChildren(debugID, [contentDebugID]);
|
||||
};
|
||||
}
|
||||
|
||||
// There are so many media events, it makes sense to just
|
||||
// maintain a list rather than create a `trapBubbledEvent` for each
|
||||
var mediaEvents = {
|
||||
@@ -452,6 +467,7 @@ function ReactDOMComponent(element) {
|
||||
this._flags = 0;
|
||||
if (__DEV__) {
|
||||
this._ancestorInfo = null;
|
||||
this._contentDebugID = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,6 +733,9 @@ ReactDOMComponent.Mixin = {
|
||||
if (contentToUse != null) {
|
||||
// TODO: Validate that text is allowed as a child of this node
|
||||
ret = escapeTextContentForBrowser(contentToUse);
|
||||
if (__DEV__) {
|
||||
setContentChildForInstrumentation.call(this, contentToUse);
|
||||
}
|
||||
} else if (childrenToUse != null) {
|
||||
var mountImages = this.mountChildren(
|
||||
childrenToUse,
|
||||
@@ -756,6 +775,9 @@ ReactDOMComponent.Mixin = {
|
||||
var childrenToUse = contentToUse != null ? null : props.children;
|
||||
if (contentToUse != null) {
|
||||
// TODO: Validate that text is allowed as a child of this node
|
||||
if (__DEV__) {
|
||||
setContentChildForInstrumentation.call(this, contentToUse);
|
||||
}
|
||||
DOMLazyTree.queueText(lazyTree, contentToUse);
|
||||
} else if (childrenToUse != null) {
|
||||
var mountImages = this.mountChildren(
|
||||
@@ -1003,17 +1025,34 @@ ReactDOMComponent.Mixin = {
|
||||
this.updateChildren(null, transaction, context);
|
||||
} else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
|
||||
this.updateTextContent('');
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
|
||||
}
|
||||
}
|
||||
|
||||
if (nextContent != null) {
|
||||
if (lastContent !== nextContent) {
|
||||
this.updateTextContent('' + nextContent);
|
||||
if (__DEV__) {
|
||||
this._contentDebugID = this._debugID + '#text';
|
||||
setContentChildForInstrumentation.call(this, nextContent);
|
||||
}
|
||||
}
|
||||
} else if (nextHtml != null) {
|
||||
if (lastHtml !== nextHtml) {
|
||||
this.updateMarkup('' + nextHtml);
|
||||
}
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
|
||||
}
|
||||
} else if (nextChildren != null) {
|
||||
if (__DEV__) {
|
||||
if (this._contentDebugID) {
|
||||
ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID);
|
||||
this._contentDebugID = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateChildren(nextChildren, transaction, context);
|
||||
}
|
||||
},
|
||||
@@ -1075,6 +1114,11 @@ ReactDOMComponent.Mixin = {
|
||||
this._rootNodeID = null;
|
||||
this._domID = null;
|
||||
this._wrapperState = null;
|
||||
|
||||
if (this._contentDebugID) {
|
||||
ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID);
|
||||
this._contentDebugID = null;
|
||||
}
|
||||
},
|
||||
|
||||
getPublicInstance: function() {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
var DOMChildrenOperations = require('DOMChildrenOperations');
|
||||
var DOMLazyTree = require('DOMLazyTree');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
|
||||
@@ -67,6 +68,8 @@ Object.assign(ReactDOMTextComponent.prototype, {
|
||||
context
|
||||
) {
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText);
|
||||
|
||||
var parentInfo;
|
||||
if (nativeParent != null) {
|
||||
parentInfo = nativeParent._ancestorInfo;
|
||||
@@ -140,6 +143,10 @@ Object.assign(ReactDOMTextComponent.prototype, {
|
||||
commentNodes[1],
|
||||
nextStringText
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onSetText(this._debugID, nextStringText);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -386,6 +386,17 @@ var ReactCompositeComponentMixin = {
|
||||
this._processChildContext(context)
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
if (this._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onSetChildren(
|
||||
this._debugID,
|
||||
this._renderedComponent._debugID !== 0 ?
|
||||
[this._renderedComponent._debugID] :
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return markup;
|
||||
},
|
||||
|
||||
@@ -853,6 +864,7 @@ var ReactCompositeComponentMixin = {
|
||||
this._renderedComponent = this._instantiateReactComponent(
|
||||
nextRenderedElement
|
||||
);
|
||||
|
||||
var nextMarkup = ReactReconciler.mountComponent(
|
||||
this._renderedComponent,
|
||||
transaction,
|
||||
@@ -860,6 +872,18 @@ var ReactCompositeComponentMixin = {
|
||||
this._nativeContainerInfo,
|
||||
this._processChildContext(context)
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
if (this._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onSetChildren(
|
||||
this._debugID,
|
||||
this._renderedComponent._debugID !== 0 ?
|
||||
[this._renderedComponent._debugID] :
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this._replaceNodeWithMarkup(oldNativeNode, nextMarkup);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
'use strict';
|
||||
|
||||
var ReactComponentEnvironment = require('ReactComponentEnvironment');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
|
||||
|
||||
var ReactCurrentOwner = require('ReactCurrentOwner');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactChildReconciler = require('ReactChildReconciler');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var flattenChildren = require('flattenChildren');
|
||||
var invariant = require('invariant');
|
||||
|
||||
@@ -137,6 +139,16 @@ function processQueue(inst, updateQueue) {
|
||||
);
|
||||
}
|
||||
|
||||
var setChildrenForInstrumentation = emptyFunction;
|
||||
if (__DEV__) {
|
||||
setChildrenForInstrumentation = function(children) {
|
||||
ReactInstrumentation.debugTool.onSetChildren(
|
||||
this._debugID,
|
||||
children ? Object.keys(children).map(key => children[key]._debugID) : []
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ReactMultiChild are capable of reconciling multiple children.
|
||||
*
|
||||
@@ -214,6 +226,7 @@ var ReactMultiChild = {
|
||||
nestedChildren, transaction, context
|
||||
);
|
||||
this._renderedChildren = children;
|
||||
|
||||
var mountImages = [];
|
||||
var index = 0;
|
||||
for (var name in children) {
|
||||
@@ -230,6 +243,11 @@ var ReactMultiChild = {
|
||||
mountImages.push(mountImage);
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
setChildrenForInstrumentation.call(this, children);
|
||||
}
|
||||
|
||||
return mountImages;
|
||||
},
|
||||
|
||||
@@ -357,6 +375,10 @@ var ReactMultiChild = {
|
||||
processQueue(this, updates);
|
||||
}
|
||||
this._renderedChildren = nextChildren;
|
||||
|
||||
if (__DEV__) {
|
||||
setChildrenForInstrumentation.call(this, nextChildren);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,9 @@ var ReactReconciler = {
|
||||
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
|
||||
}
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onMountComponent(internalInstance);
|
||||
if (internalInstance._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID);
|
||||
}
|
||||
}
|
||||
return markup;
|
||||
},
|
||||
@@ -76,7 +78,9 @@ var ReactReconciler = {
|
||||
ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
|
||||
internalInstance.unmountComponent(safely);
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onUnmountComponent(internalInstance);
|
||||
if (internalInstance._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -128,7 +132,9 @@ var ReactReconciler = {
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
|
||||
if (internalInstance._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -145,7 +151,9 @@ var ReactReconciler = {
|
||||
) {
|
||||
internalInstance.performUpdateIfNecessary(transaction);
|
||||
if (__DEV__) {
|
||||
ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
|
||||
if (internalInstance._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
var ReactCompositeComponent = require('ReactCompositeComponent');
|
||||
var ReactEmptyComponent = require('ReactEmptyComponent');
|
||||
var ReactNativeComponent = require('ReactNativeComponent');
|
||||
var ReactInstrumentation = require('ReactInstrumentation');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
@@ -40,6 +41,21 @@ function getDeclarationErrorAddendum(owner) {
|
||||
return '';
|
||||
}
|
||||
|
||||
function getDisplayName(instance) {
|
||||
var element = instance._currentElement;
|
||||
if (element == null) {
|
||||
return '#empty';
|
||||
} else if (typeof element === 'string' || typeof element === 'number') {
|
||||
return '#text';
|
||||
} else if (typeof element.type === 'string') {
|
||||
return element.type;
|
||||
} else if (instance.getName) {
|
||||
return instance.getName() || 'Unknown';
|
||||
} else {
|
||||
return element.type.displayName || element.type.name || 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the type reference is a known internal type. I.e. not a user
|
||||
* provided composite type.
|
||||
@@ -56,6 +72,8 @@ function isInternalComponentType(type) {
|
||||
);
|
||||
}
|
||||
|
||||
var nextDebugID = 1;
|
||||
|
||||
/**
|
||||
* Given a ReactNode, create an instance that will actually be mounted.
|
||||
*
|
||||
@@ -66,7 +84,8 @@ function isInternalComponentType(type) {
|
||||
function instantiateReactComponent(node) {
|
||||
var instance;
|
||||
|
||||
if (node === null || node === false) {
|
||||
var isEmpty = node === null || node === false;
|
||||
if (isEmpty) {
|
||||
instance = ReactEmptyComponent.create(instantiateReactComponent);
|
||||
} else if (typeof node === 'object') {
|
||||
var element = node;
|
||||
@@ -121,6 +140,18 @@ function instantiateReactComponent(node) {
|
||||
instance._warnedAboutRefsInRender = false;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
var debugID = isEmpty ? 0 : nextDebugID++;
|
||||
instance._debugID = debugID;
|
||||
|
||||
var displayName = getDisplayName(instance);
|
||||
ReactInstrumentation.debugTool.onSetDisplayName(debugID, displayName);
|
||||
var owner = node && node._owner;
|
||||
if (owner) {
|
||||
ReactInstrumentation.debugTool.onSetOwner(debugID, owner._debugID);
|
||||
}
|
||||
}
|
||||
|
||||
// Internal instances should fully constructed at this point, so they should
|
||||
// not get any new fields added to them at this point.
|
||||
if (__DEV__) {
|
||||
|
||||
Reference in New Issue
Block a user