diff --git a/src/browser/ui/ReactDOMComponent.js b/src/browser/ui/ReactDOMComponent.js index b9cf620548..03575c67c0 100644 --- a/src/browser/ui/ReactDOMComponent.js +++ b/src/browser/ui/ReactDOMComponent.js @@ -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] ? '' : ''; - 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] ? '' : ''; + 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, diff --git a/src/browser/ui/ReactDOMIDOperations.js b/src/browser/ui/ReactDOMIDOperations.js index b5c37d47fc..6705433e48 100644 --- a/src/browser/ui/ReactDOMIDOperations.js +++ b/src/browser/ui/ReactDOMIDOperations.js @@ -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} 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; diff --git a/src/browser/ui/ReactMount.js b/src/browser/ui/ReactMount.js index 41d5538507..90a874622d 100644 --- a/src/browser/ui/ReactMount.js +++ b/src/browser/ui/ReactMount.js @@ -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', diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index bcfb322454..7fef0669be 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -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, diff --git a/src/core/ReactUpdates.js b/src/core/ReactUpdates.js index f57353731d..e8d59f2d6b 100644 --- a/src/core/ReactUpdates.js +++ b/src/core/ReactUpdates.js @@ -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 ); /** diff --git a/src/test/ReactPerf.js b/src/test/ReactPerf.js index 34e3db65c1..ceec3f8678 100644 --- a/src/test/ReactPerf.js +++ b/src/test/ReactPerf.js @@ -29,6 +29,26 @@ var ReactPerf = { */ storedMeasure: _noMeasure, + /** + * @param {object} object + * @param {string} objectName + * @param {object} 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. *