Preserve Implicit Method Names

Summary:
Changes the way we instrument methods for `ReactPerf` so that developer tools can assign implicit method names to measured functions.

Reviewers: @zpao @sebmarkbage
This commit is contained in:
yungsters
2014-11-04 13:43:49 -08:00
parent e3e0bf5de2
commit bda199de04
6 changed files with 389 additions and 391 deletions
+37 -40
View File
@@ -171,28 +171,24 @@ ReactDOMComponent.Mixin = {
* @param {number} mountDepth number of components in the owner hierarchy
* @return {string} The computed markup.
*/
mountComponent: ReactPerf.measure(
'ReactDOMComponent',
'mountComponent',
function(rootID, transaction, mountDepth, context) {
invariant(context !== undefined, "Context is required parameter");
ReactComponent.Mixin.mountComponent.call(
this,
rootID,
transaction,
mountDepth,
context
);
this._rootNodeID = rootID;
assertValidProps(this._currentElement.props);
var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
return (
this._createOpenTagMarkupAndPutListeners(transaction) +
this._createContentMarkup(transaction, context) +
closeTag
);
}
),
mountComponent: function(rootID, transaction, mountDepth, context) {
invariant(context !== undefined, "Context is required parameter");
ReactComponent.Mixin.mountComponent.call(
this,
rootID,
transaction,
mountDepth,
context
);
this._rootNodeID = rootID;
assertValidProps(this._currentElement.props);
var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
return (
this._createOpenTagMarkupAndPutListeners(transaction) +
this._createContentMarkup(transaction, context) +
closeTag
);
},
/**
* Creates markup for the open tag and all attributes.
@@ -319,24 +315,20 @@ ReactDOMComponent.Mixin = {
* @internal
* @overridable
*/
updateComponent: ReactPerf.measure(
'ReactDOMComponent',
'updateComponent',
function(transaction, prevElement, nextElement, context) {
if(context === undefined) throw new Error("Context required for mounting");
if(context === null) throw new Error("Assert: context is not null");
assertValidProps(this._currentElement.props);
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevElement,
nextElement,
context
);
this._updateDOMProperties(prevElement.props, transaction);
this._updateDOMChildren(prevElement.props, transaction, context);
}
),
updateComponent: function(transaction, prevElement, nextElement, context) {
if(context === undefined) throw new Error("Context required for mounting");
if(context === null) throw new Error("Assert: context is not null");
assertValidProps(this._currentElement.props);
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevElement,
nextElement,
context
);
this._updateDOMProperties(prevElement.props, transaction);
this._updateDOMChildren(prevElement.props, transaction, context);
},
/**
* Reconciles the properties by detecting differences in property values and
@@ -504,6 +496,11 @@ ReactDOMComponent.Mixin = {
};
ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
mountComponent: 'mountComponent',
updateComponent: 'updateComponent'
});
assign(
ReactDOMComponent.prototype,
ReactComponent.Mixin,
+53 -71
View File
@@ -50,27 +50,23 @@ var ReactDOMIDOperations = {
* @param {*} value New value of the property.
* @internal
*/
updatePropertyByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updatePropertyByID',
function(id, name, value) {
var node = ReactMount.getNode(id);
invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
);
updatePropertyByID: function(id, name, value) {
var node = ReactMount.getNode(id);
invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
);
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertantly setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (value != null) {
DOMPropertyOperations.setValueForProperty(node, name, value);
} else {
DOMPropertyOperations.deleteValueForProperty(node, name);
}
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertantly setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (value != null) {
DOMPropertyOperations.setValueForProperty(node, name, value);
} else {
DOMPropertyOperations.deleteValueForProperty(node, name);
}
),
},
/**
* Updates a DOM node to remove a property. This should only be used to remove
@@ -80,19 +76,15 @@ var ReactDOMIDOperations = {
* @param {string} name A property name to remove, see `DOMProperty`.
* @internal
*/
deletePropertyByID: ReactPerf.measure(
'ReactDOMIDOperations',
'deletePropertyByID',
function(id, name, value) {
var node = ReactMount.getNode(id);
invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
);
DOMPropertyOperations.deleteValueForProperty(node, name, value);
}
),
deletePropertyByID: function(id, name, value) {
var node = ReactMount.getNode(id);
invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
);
DOMPropertyOperations.deleteValueForProperty(node, name, value);
},
/**
* Updates a DOM node with new style values. If a value is specified as '',
@@ -102,14 +94,10 @@ var ReactDOMIDOperations = {
* @param {object} styles Mapping from styles to values.
* @internal
*/
updateStylesByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateStylesByID',
function(id, styles) {
var node = ReactMount.getNode(id);
CSSPropertyOperations.setValueForStyles(node, styles);
}
),
updateStylesByID: function(id, styles) {
var node = ReactMount.getNode(id);
CSSPropertyOperations.setValueForStyles(node, styles);
},
/**
* Updates a DOM node's innerHTML.
@@ -118,14 +106,10 @@ var ReactDOMIDOperations = {
* @param {string} html An HTML string.
* @internal
*/
updateInnerHTMLByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateInnerHTMLByID',
function(id, html) {
var node = ReactMount.getNode(id);
setInnerHTML(node, html);
}
),
updateInnerHTMLByID: function(id, html) {
var node = ReactMount.getNode(id);
setInnerHTML(node, html);
},
/**
* Updates a DOM node's text content set by `props.content`.
@@ -134,14 +118,10 @@ var ReactDOMIDOperations = {
* @param {string} content Text content.
* @internal
*/
updateTextContentByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateTextContentByID',
function(id, content) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.updateTextContent(node, content);
}
),
updateTextContentByID: function(id, content) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.updateTextContent(node, content);
},
/**
* Replaces a DOM node that exists in the document with markup.
@@ -151,14 +131,10 @@ var ReactDOMIDOperations = {
* @internal
* @see {Danger.dangerouslyReplaceNodeWithMarkup}
*/
dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
'ReactDOMIDOperations',
'dangerouslyReplaceNodeWithMarkupByID',
function(id, markup) {
dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
}
),
},
/**
* Updates a component's children by processing a series of updates.
@@ -167,16 +143,22 @@ var ReactDOMIDOperations = {
* @param {array<string>} markup List of markup strings.
* @internal
*/
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
'ReactDOMIDOperations',
'dangerouslyProcessChildrenUpdates',
function(updates, markup) {
for (var i = 0; i < updates.length; i++) {
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
}
DOMChildrenOperations.processUpdates(updates, markup);
dangerouslyProcessChildrenUpdates: function(updates, markup) {
for (var i = 0; i < updates.length; i++) {
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
}
)
DOMChildrenOperations.processUpdates(updates, markup);
}
};
ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
updatePropertyByID: 'updatePropertyByID',
deletePropertyByID: 'deletePropertyByID',
updateStylesByID: 'updateStylesByID',
updateInnerHTMLByID: 'updateInnerHTMLByID',
updateTextContentByID: 'updateTextContentByID',
dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
});
module.exports = ReactDOMIDOperations;
+89 -91
View File
@@ -319,50 +319,47 @@ var ReactMount = {
* @param {boolean} shouldReuseMarkup if we should skip the markup insertion
* @return {ReactComponent} nextComponent
*/
_renderNewRootComponent: ReactPerf.measure(
'ReactMount',
'_renderNewRootComponent',
function(
nextComponent,
container,
shouldReuseMarkup) {
// Various parts of our code (such as ReactCompositeComponent's
// _renderValidatedComponent) assume that calls to render aren't nested;
// verify that that's the case.
warning(
ReactCurrentOwner.current == null,
'_renderNewRootComponent(): Render methods should be a pure function ' +
'of props and state; triggering nested component updates from ' +
'render is not allowed. If necessary, trigger nested updates in ' +
'componentDidUpdate.'
);
_renderNewRootComponent: function(
nextComponent,
container,
shouldReuseMarkup
) {
// Various parts of our code (such as ReactCompositeComponent's
// _renderValidatedComponent) assume that calls to render aren't nested;
// verify that that's the case.
warning(
ReactCurrentOwner.current == null,
'_renderNewRootComponent(): Render methods should be a pure function ' +
'of props and state; triggering nested component updates from ' +
'render is not allowed. If necessary, trigger nested updates in ' +
'componentDidUpdate.'
);
var componentInstance = instantiateReactComponent(nextComponent, null);
var reactRootID = ReactMount._registerComponent(
componentInstance,
container
);
var componentInstance = instantiateReactComponent(nextComponent, null);
var reactRootID = ReactMount._registerComponent(
componentInstance,
container
);
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
transaction.perform(
mountComponentIntoNode,
componentInstance,
reactRootID,
container,
transaction,
shouldReuseMarkup
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
transaction.perform(
mountComponentIntoNode,
componentInstance,
reactRootID,
container,
transaction,
shouldReuseMarkup
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
if (__DEV__) {
// Record the root element in case it later gets transplanted.
rootElementsByReactRootID[reactRootID] =
getReactRootElementInContainer(container);
}
return componentInstance;
if (__DEV__) {
// Record the root element in case it later gets transplanted.
rootElementsByReactRootID[reactRootID] =
getReactRootElementInContainer(container);
}
),
return componentInstance;
},
/**
* Renders a React component into the DOM in the supplied `container`.
@@ -711,62 +708,58 @@ var ReactMount = {
);
},
_mountImageIntoNode: ReactPerf.measure(
'ReactMount',
'_mountImageIntoNode',
function(markup, container, shouldReuseMarkup) {
invariant(
container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
),
'mountComponentIntoNode(...): Target container is not valid.'
);
_mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
invariant(
container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
),
'mountComponentIntoNode(...): Target container is not valid.'
);
if (shouldReuseMarkup) {
if (ReactMarkupChecksum.canReuseMarkup(
markup,
getReactRootElementInContainer(container))) {
return;
} else {
invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document using ' +
'server rendering but the checksum was invalid. This usually ' +
'means you rendered a different component type or props on ' +
'the client from the one on the server, or your render() ' +
'methods are impure. React cannot handle this case due to ' +
'cross-browser quirks by rendering at the document root. You ' +
'should look for environment dependent code in your components ' +
'and ensure the props are the same client and server side.'
if (shouldReuseMarkup) {
if (ReactMarkupChecksum.canReuseMarkup(
markup,
getReactRootElementInContainer(container))) {
return;
} else {
invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document using ' +
'server rendering but the checksum was invalid. This usually ' +
'means you rendered a different component type or props on ' +
'the client from the one on the server, or your render() ' +
'methods are impure. React cannot handle this case due to ' +
'cross-browser quirks by rendering at the document root. You ' +
'should look for environment dependent code in your components ' +
'and ensure the props are the same client and server side.'
);
if (__DEV__) {
console.warn(
'React attempted to use reuse markup in a container but the ' +
'checksum was invalid. This generally means that you are ' +
'using server rendering and the markup generated on the ' +
'server was not what the client was expecting. React injected ' +
'new markup to compensate which works but you have lost many ' +
'of the benefits of server rendering. Instead, figure out ' +
'why the markup being generated is different on the client ' +
'or server.'
);
if (__DEV__) {
console.warn(
'React attempted to use reuse markup in a container but the ' +
'checksum was invalid. This generally means that you are ' +
'using server rendering and the markup generated on the ' +
'server was not what the client was expecting. React injected ' +
'new markup to compensate which works but you have lost many ' +
'of the benefits of server rendering. Instead, figure out ' +
'why the markup being generated is different on the client ' +
'or server.'
);
}
}
}
invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document but ' +
'you didn\'t use server rendering. We can\'t do this ' +
'without using server rendering due to cross-browser quirks. ' +
'See renderComponentToString() for server rendering.'
);
setInnerHTML(container, markup);
}
),
invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document but ' +
'you didn\'t use server rendering. We can\'t do this ' +
'without using server rendering due to cross-browser quirks. ' +
'See renderComponentToString() for server rendering.'
);
setInnerHTML(container, markup);
},
/**
* React ID utilities.
@@ -785,6 +778,11 @@ var ReactMount = {
purgeID: purgeID
};
ReactPerf.measureMethods(ReactMount, 'ReactMount', {
_renderNewRootComponent: '_renderNewRootComponent',
_mountImageIntoNode: '_mountImageIntoNode'
});
// Deprecations (remove for 0.13)
ReactMount.renderComponent = deprecated(
'ReactMount',
+168 -168
View File
@@ -157,85 +157,81 @@ var ReactCompositeComponentMixin = assign({},
* @final
* @internal
*/
mountComponent: ReactPerf.measure(
'ReactCompositeComponent',
'mountComponent',
function(rootID, transaction, mountDepth, context) {
invariant(context !== undefined, "Context is required parameter");
ReactComponent.Mixin.mountComponent.call(
this,
rootID,
transaction,
mountDepth,
context
);
mountComponent: function(rootID, transaction, mountDepth, context) {
invariant(context !== undefined, "Context is required parameter");
ReactComponent.Mixin.mountComponent.call(
this,
rootID,
transaction,
mountDepth,
context
);
this._context = context;
this._rootNodeID = rootID;
this._context = context;
this._rootNodeID = rootID;
var inst = this._instance;
var inst = this._instance;
// Store a reference from the instance back to the internal representation
ReactInstanceMap.set(inst, this);
// Store a reference from the instance back to the internal representation
ReactInstanceMap.set(inst, this);
this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
inst.context = this._processContext(this._currentElement._context);
if (__DEV__) {
this._warnIfContextsDiffer(this._currentElement._context, context);
}
inst.props = this._processProps(this._currentElement.props);
var initialState = inst.getInitialState ? inst.getInitialState() : null;
if (__DEV__) {
// We allow auto-mocks to proceed as if they're returning null.
if (typeof initialState === 'undefined' &&
inst.getInitialState._isMockFunction) {
// This is probably bad practice. Consider warning here and
// deprecating this convenience.
initialState = null;
}
}
invariant(
typeof initialState === 'object' && !Array.isArray(initialState),
'%s.getInitialState(): must return an object or null',
inst.constructor.displayName || 'ReactCompositeComponent'
);
inst.state = initialState;
this._pendingState = null;
this._pendingForceUpdate = false;
if (inst.componentWillMount) {
inst.componentWillMount();
// When mounting, calls to `setState` by `componentWillMount` will set
// `this._pendingState` without triggering a re-render.
if (this._pendingState) {
inst.state = this._pendingState;
this._pendingState = null;
}
}
var renderedElement = this._renderValidatedComponent();
this._renderedComponent = this._instantiateReactComponent(
renderedElement,
this._currentElement.type // The wrapping type
);
// Done with mounting, `setState` will now trigger UI changes.
this._compositeLifeCycleState = null;
var markup = this._renderedComponent.mountComponent(
rootID,
transaction,
mountDepth + 1,
this._processChildContext(context)
);
if (inst.componentDidMount) {
transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
}
return markup;
inst.context = this._processContext(this._currentElement._context);
if (__DEV__) {
this._warnIfContextsDiffer(this._currentElement._context, context);
}
),
inst.props = this._processProps(this._currentElement.props);
var initialState = inst.getInitialState ? inst.getInitialState() : null;
if (__DEV__) {
// We allow auto-mocks to proceed as if they're returning null.
if (typeof initialState === 'undefined' &&
inst.getInitialState._isMockFunction) {
// This is probably bad practice. Consider warning here and
// deprecating this convenience.
initialState = null;
}
}
invariant(
typeof initialState === 'object' && !Array.isArray(initialState),
'%s.getInitialState(): must return an object or null',
inst.constructor.displayName || 'ReactCompositeComponent'
);
inst.state = initialState;
this._pendingState = null;
this._pendingForceUpdate = false;
if (inst.componentWillMount) {
inst.componentWillMount();
// When mounting, calls to `setState` by `componentWillMount` will set
// `this._pendingState` without triggering a re-render.
if (this._pendingState) {
inst.state = this._pendingState;
this._pendingState = null;
}
}
var renderedElement = this._renderValidatedComponent();
this._renderedComponent = this._instantiateReactComponent(
renderedElement,
this._currentElement.type // The wrapping type
);
// Done with mounting, `setState` will now trigger UI changes.
this._compositeLifeCycleState = null;
var markup = this._renderedComponent.mountComponent(
rootID,
transaction,
mountDepth + 1,
this._processChildContext(context)
);
if (inst.componentDidMount) {
transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
}
return markup;
},
/**
* Releases any resources allocated by `mountComponent`.
@@ -627,84 +623,82 @@ var ReactCompositeComponentMixin = assign({},
* @internal
* @overridable
*/
updateComponent: ReactPerf.measure(
'ReactCompositeComponent',
'updateComponent',
function(
transaction,
prevParentElement,
nextParentElement,
prevUnmaskedContext,
nextUnmaskedContext) {
// Update refs regardless of what shouldComponentUpdate returns
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevParentElement,
nextParentElement,
prevUnmaskedContext,
nextUnmaskedContext
);
updateComponent: function(
transaction,
prevParentElement,
nextParentElement,
prevUnmaskedContext,
nextUnmaskedContext
) {
// Update refs regardless of what shouldComponentUpdate returns
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevParentElement,
nextParentElement,
prevUnmaskedContext,
nextUnmaskedContext
);
var inst = this._instance;
var inst = this._instance;
var prevContext = inst.context;
var prevProps = inst.props;
var nextContext = prevContext;
var nextProps = prevProps;
// Distinguish between a props update versus a simple state update
if (prevParentElement !== nextParentElement) {
nextContext = this._processContext(nextParentElement._context);
nextProps = this._processProps(nextParentElement.props);
var prevContext = inst.context;
var prevProps = inst.props;
var nextContext = prevContext;
var nextProps = prevProps;
// Distinguish between a props update versus a simple state update
if (prevParentElement !== nextParentElement) {
nextContext = this._processContext(nextParentElement._context);
nextProps = this._processProps(nextParentElement.props);
this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
if (inst.componentWillReceiveProps) {
inst.componentWillReceiveProps(nextProps, nextContext);
}
this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
if (inst.componentWillReceiveProps) {
inst.componentWillReceiveProps(nextProps, nextContext);
}
}
this._compositeLifeCycleState = null;
this._compositeLifeCycleState = null;
var nextState = this._pendingState || inst.state;
this._pendingState = null;
var nextState = this._pendingState || inst.state;
this._pendingState = null;
var shouldUpdate =
this._pendingForceUpdate ||
!inst.shouldComponentUpdate ||
inst.shouldComponentUpdate(nextProps, nextState, nextContext);
var shouldUpdate =
this._pendingForceUpdate ||
!inst.shouldComponentUpdate ||
inst.shouldComponentUpdate(nextProps, nextState, nextContext);
if (__DEV__) {
if (typeof shouldUpdate === "undefined") {
console.warn(
(inst.constructor.displayName || 'ReactCompositeComponent') +
'.shouldComponentUpdate(): Returned undefined instead of a ' +
'boolean value. Make sure to return true or false.'
);
}
if (__DEV__) {
if (typeof shouldUpdate === "undefined") {
console.warn(
(inst.constructor.displayName || 'ReactCompositeComponent') +
'.shouldComponentUpdate(): Returned undefined instead of a ' +
'boolean value. Make sure to return true or false.'
);
}
}
if (!shouldUpdate) {
// If it's determined that a component should not update, we still want
// to set props and state but we shortcut the rest of the update.
this._currentElement = nextParentElement;
this._context = nextUnmaskedContext;
inst.props = nextProps;
inst.state = nextState;
inst.context = nextContext;
return;
}
if (!shouldUpdate) {
// If it's determined that a component should not update, we still want
// to set props and state but we shortcut the rest of the update.
this._currentElement = nextParentElement;
this._context = nextUnmaskedContext;
inst.props = nextProps;
inst.state = nextState;
inst.context = nextContext;
return;
}
this._pendingForceUpdate = false;
// Will set `this.props`, `this.state` and `this.context`.
this._performComponentUpdate(
nextParentElement,
nextProps,
nextState,
nextContext,
transaction,
nextUnmaskedContext
);
}),
this._pendingForceUpdate = false;
// Will set `this.props`, `this.state` and `this.context`.
this._performComponentUpdate(
nextParentElement,
nextProps,
nextState,
nextContext,
transaction,
nextUnmaskedContext
);
},
/**
* Merges new props and state, notifies delegate methods of update and
@@ -816,35 +810,31 @@ var ReactCompositeComponentMixin = assign({},
/**
* @private
*/
_renderValidatedComponent: ReactPerf.measure(
'ReactCompositeComponent',
'_renderValidatedComponent',
function() {
var renderedComponent;
var previousContext = ReactContext.current;
ReactContext.current = this._processChildContext(
this._currentElement._context
);
ReactCurrentOwner.current = this;
var inst = this._instance;
try {
renderedComponent =
this._renderValidatedComponentWithoutOwnerOrContext();
} finally {
ReactContext.current = previousContext;
ReactCurrentOwner.current = null;
}
invariant(
// TODO: An `isValidNode` function would probably be more appropriate
renderedComponent === null || renderedComponent === false ||
ReactElement.isValidElement(renderedComponent),
'%s.render(): A valid ReactComponent must be returned. You may have ' +
'returned undefined, an array or some other invalid object.',
inst.constructor.displayName || 'ReactCompositeComponent'
);
return renderedComponent;
_renderValidatedComponent: function() {
var renderedComponent;
var previousContext = ReactContext.current;
ReactContext.current = this._processChildContext(
this._currentElement._context
);
ReactCurrentOwner.current = this;
var inst = this._instance;
try {
renderedComponent =
this._renderValidatedComponentWithoutOwnerOrContext();
} finally {
ReactContext.current = previousContext;
ReactCurrentOwner.current = null;
}
),
invariant(
// TODO: An `isValidNode` function would probably be more appropriate
renderedComponent === null || renderedComponent === false ||
ReactElement.isValidElement(renderedComponent),
'%s.render(): A valid ReactComponent must be returned. You may have ' +
'returned undefined, an array or some other invalid object.',
inst.constructor.displayName || 'ReactCompositeComponent'
);
return renderedComponent;
},
/**
* Lazily allocates the refs object and stores `component` as `ref`.
@@ -1001,6 +991,16 @@ var ShallowMixin = assign({},
});
ReactPerf.measureMethods(
ReactCompositeComponentMixin,
'ReactCompositeComponent',
{
mountComponent: 'mountComponent',
updateComponent: 'updateComponent',
_renderValidatedComponent: '_renderValidatedComponent'
}
);
var ReactCompositeComponent = {
LifeCycle: CompositeLifeCycle,
+22 -21
View File
@@ -159,30 +159,31 @@ function runBatchedUpdates(transaction) {
}
}
var flushBatchedUpdates = ReactPerf.measure(
'ReactUpdates',
'flushBatchedUpdates',
function() {
// ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
// array and perform any updates enqueued by mount-ready handlers (i.e.,
// componentDidUpdate) but we need to check here too in order to catch
// updates enqueued by setState callbacks and asap calls.
while (dirtyComponents.length || asapEnqueued) {
if (dirtyComponents.length) {
var transaction = ReactUpdatesFlushTransaction.getPooled();
transaction.perform(runBatchedUpdates, null, transaction);
ReactUpdatesFlushTransaction.release(transaction);
}
var flushBatchedUpdates = function() {
// ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
// array and perform any updates enqueued by mount-ready handlers (i.e.,
// componentDidUpdate) but we need to check here too in order to catch
// updates enqueued by setState callbacks and asap calls.
while (dirtyComponents.length || asapEnqueued) {
if (dirtyComponents.length) {
var transaction = ReactUpdatesFlushTransaction.getPooled();
transaction.perform(runBatchedUpdates, null, transaction);
ReactUpdatesFlushTransaction.release(transaction);
}
if (asapEnqueued) {
asapEnqueued = false;
var queue = asapCallbackQueue;
asapCallbackQueue = CallbackQueue.getPooled();
queue.notifyAll();
CallbackQueue.release(queue);
}
if (asapEnqueued) {
asapEnqueued = false;
var queue = asapCallbackQueue;
asapCallbackQueue = CallbackQueue.getPooled();
queue.notifyAll();
CallbackQueue.release(queue);
}
}
};
flushBatchedUpdates = ReactPerf.measure(
'ReactUpdates',
'flushBatchedUpdates',
flushBatchedUpdates
);
/**
+20
View File
@@ -29,6 +29,26 @@ var ReactPerf = {
*/
storedMeasure: _noMeasure,
/**
* @param {object} object
* @param {string} objectName
* @param {object<string>} methodNames
*/
measureMethods: function(object, objectName, methodNames) {
if (__DEV__) {
for (var key in methodNames) {
if (!methodNames.hasOwnProperty(key)) {
continue;
}
object[key] = ReactPerf.measure(
objectName,
methodNames[key],
object[key]
);
}
}
},
/**
* Use this to wrap methods you want to measure. Zero overhead in production.
*