2017-05-03 15:35:00 +02:00
/ * *
* Copyright 2013 - 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 .
*
* /
'use strict' ;
var _prodInvariant = require ( './reactProdInvariant' ) ,
_assign = require ( 'object-assign' ) ;
var React = require ( 'react/lib/React' ) ;
var ReactComponentEnvironment = require ( './ReactComponentEnvironment' ) ;
var ReactCurrentOwner = require ( 'react/lib/ReactCurrentOwner' ) ;
var ReactErrorUtils = require ( './ReactErrorUtils' ) ;
var ReactInstanceMap = require ( './ReactInstanceMap' ) ;
var ReactInstrumentation = require ( './ReactInstrumentation' ) ;
var ReactNodeTypes = require ( './ReactNodeTypes' ) ;
var ReactReconciler = require ( './ReactReconciler' ) ;
if ( process . env . NODE _ENV !== 'production' ) {
var checkReactTypeSpec = require ( './checkReactTypeSpec' ) ;
}
var emptyObject = require ( 'fbjs/lib/emptyObject' ) ;
var invariant = require ( 'fbjs/lib/invariant' ) ;
var shallowEqual = require ( 'fbjs/lib/shallowEqual' ) ;
var shouldUpdateReactComponent = require ( './shouldUpdateReactComponent' ) ;
var warning = require ( 'fbjs/lib/warning' ) ;
var CompositeTypes = {
ImpureClass : 0 ,
PureClass : 1 ,
StatelessFunctional : 2
} ;
function StatelessComponent ( Component ) { }
StatelessComponent . prototype . render = function ( ) {
var Component = ReactInstanceMap . get ( this ) . _currentElement . type ;
var element = Component ( this . props , this . context , this . updater ) ;
warnIfInvalidElement ( Component , element ) ;
return element ;
} ;
function warnIfInvalidElement ( Component , element ) {
if ( process . env . NODE _ENV !== 'production' ) {
process . env . NODE _ENV !== 'production' ? warning ( element === null || element === false || React . isValidElement ( element ) , '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.' , Component . displayName || Component . name || 'Component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( ! Component . childContextTypes , '%s(...): childContextTypes cannot be defined on a functional component.' , Component . displayName || Component . name || 'Component' ) : void 0 ;
}
}
function shouldConstruct ( Component ) {
return ! ! ( Component . prototype && Component . prototype . isReactComponent ) ;
}
function isPureComponent ( Component ) {
return ! ! ( Component . prototype && Component . prototype . isPureReactComponent ) ;
}
// Separated into a function to contain deoptimizations caused by try/finally.
function measureLifeCyclePerf ( fn , debugID , timerType ) {
if ( debugID === 0 ) {
// Top-level wrappers (see ReactMount) and empty components (see
// ReactDOMEmptyComponent) are invisible to hooks and devtools.
// Both are implementation details that should go away in the future.
return fn ( ) ;
}
ReactInstrumentation . debugTool . onBeginLifeCycleTimer ( debugID , timerType ) ;
try {
return fn ( ) ;
} finally {
ReactInstrumentation . debugTool . onEndLifeCycleTimer ( debugID , timerType ) ;
}
}
/ * *
* -- -- -- -- -- -- -- -- -- The Life - Cycle of a Composite Component -- -- -- -- -- -- -- -- --
*
* - constructor : Initialization of state . The instance is now retained .
* - componentWillMount
* - render
* - [ children ' s constructors ]
* - [ children ' s componentWillMount and render ]
* - [ children ' s componentDidMount ]
* - componentDidMount
*
* Update Phases :
* - componentWillReceiveProps ( only called if parent updated )
* - shouldComponentUpdate
* - componentWillUpdate
* - render
* - [ children ' s constructors or receive props phases ]
* - componentDidUpdate
*
* - componentWillUnmount
* - [ children ' s componentWillUnmount ]
* - [ children destroyed ]
* - ( destroyed ) : The instance is now blank , released by React and ready for GC .
*
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
* /
/ * *
* An incrementing ID assigned to each component when it is mounted . This is
* used to enforce the order in which ` ReactUpdates ` updates dirty components .
*
* @ private
* /
var nextMountID = 1 ;
/ * *
* @ lends { ReactCompositeComponent . prototype }
* /
var ReactCompositeComponent = {
/ * *
* Base constructor for all composite component .
*
* @ param { ReactElement } element
* @ final
* @ internal
* /
construct : function ( element ) {
this . _currentElement = element ;
this . _rootNodeID = 0 ;
this . _compositeType = null ;
this . _instance = null ;
this . _hostParent = null ;
this . _hostContainerInfo = null ;
// See ReactUpdateQueue
this . _updateBatchNumber = null ;
this . _pendingElement = null ;
this . _pendingStateQueue = null ;
this . _pendingReplaceState = false ;
this . _pendingForceUpdate = false ;
this . _renderedNodeType = null ;
this . _renderedComponent = null ;
this . _context = null ;
this . _mountOrder = 0 ;
this . _topLevelWrapper = null ;
// See ReactUpdates and ReactUpdateQueue.
this . _pendingCallbacks = null ;
// ComponentWillUnmount shall only be called once
this . _calledComponentWillUnmount = false ;
if ( process . env . NODE _ENV !== 'production' ) {
this . _warnedAboutRefsInRender = false ;
}
} ,
/ * *
* Initializes the component , renders markup , and registers event listeners .
*
* @ param { ReactReconcileTransaction | ReactServerRenderingTransaction } transaction
* @ param { ? object } hostParent
* @ param { ? object } hostContainerInfo
* @ param { ? object } context
* @ return { ? string } Rendered markup to be inserted into the DOM .
* @ final
* @ internal
* /
mountComponent : function ( transaction , hostParent , hostContainerInfo , context ) {
var _this = this ;
this . _context = context ;
this . _mountOrder = nextMountID ++ ;
this . _hostParent = hostParent ;
this . _hostContainerInfo = hostContainerInfo ;
var publicProps = this . _currentElement . props ;
var publicContext = this . _processContext ( context ) ;
var Component = this . _currentElement . type ;
var updateQueue = transaction . getUpdateQueue ( ) ;
// Initialize the public class
var doConstruct = shouldConstruct ( Component ) ;
var inst = this . _constructComponent ( doConstruct , publicProps , publicContext , updateQueue ) ;
var renderedElement ;
// Support functional components
if ( ! doConstruct && ( inst == null || inst . render == null ) ) {
renderedElement = inst ;
warnIfInvalidElement ( Component , renderedElement ) ;
! ( inst === null || inst === false || React . isValidElement ( inst ) ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.' , Component . displayName || Component . name || 'Component' ) : _prodInvariant ( '105' , Component . displayName || Component . name || 'Component' ) : void 0 ;
inst = new StatelessComponent ( Component ) ;
this . _compositeType = CompositeTypes . StatelessFunctional ;
} else {
if ( isPureComponent ( Component ) ) {
this . _compositeType = CompositeTypes . PureClass ;
} else {
this . _compositeType = CompositeTypes . ImpureClass ;
}
}
if ( process . env . NODE _ENV !== 'production' ) {
// This will throw later in _renderValidatedComponent, but add an early
// warning now to help debugging
if ( inst . render == null ) {
process . env . NODE _ENV !== 'production' ? warning ( false , '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.' , Component . displayName || Component . name || 'Component' ) : void 0 ;
}
var propsMutated = inst . props !== publicProps ;
var componentName = Component . displayName || Component . name || 'Component' ;
2017-08-14 05:01:11 +02:00
process . env . NODE _ENV !== 'production' ? warning ( inst . props === undefined || ! propsMutated , '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed." , componentName , componentName ) : void 0 ;
2017-05-03 15:35:00 +02:00
}
// These should be set up in the constructor, but as a convenience for
// simpler class abstractions, we set them up after the fact.
inst . props = publicProps ;
inst . context = publicContext ;
inst . refs = emptyObject ;
inst . updater = updateQueue ;
this . _instance = inst ;
// Store a reference from the instance back to the internal representation
ReactInstanceMap . set ( inst , this ) ;
if ( process . env . NODE _ENV !== 'production' ) {
// Since plain JS classes are defined without any special initialization
// logic, we can not catch common errors early. Therefore, we have to
// catch them here, at initialization time, instead.
process . env . NODE _ENV !== 'production' ? warning ( ! inst . getInitialState || inst . getInitialState . isReactClassApproved || inst . state , 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?' , this . getName ( ) || 'a component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( ! inst . getDefaultProps || inst . getDefaultProps . isReactClassApproved , 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.' , this . getName ( ) || 'a component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( ! inst . propTypes , 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.' , this . getName ( ) || 'a component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( ! inst . contextTypes , 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.' , this . getName ( ) || 'a component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( typeof inst . componentShouldUpdate !== 'function' , '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.' , this . getName ( ) || 'A component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( typeof inst . componentDidUnmount !== 'function' , '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?' , this . getName ( ) || 'A component' ) : void 0 ;
process . env . NODE _ENV !== 'production' ? warning ( typeof inst . componentWillRecieveProps !== 'function' , '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?' , this . getName ( ) || 'A component' ) : void 0 ;
}
var initialState = inst . state ;
if ( initialState === undefined ) {
inst . state = initialState = null ;
}
! ( typeof initialState === 'object' && ! Array . isArray ( initialState ) ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s.state: must be set to an object or null' , this . getName ( ) || 'ReactCompositeComponent' ) : _prodInvariant ( '106' , this . getName ( ) || 'ReactCompositeComponent' ) : void 0 ;
this . _pendingStateQueue = null ;
this . _pendingReplaceState = false ;
this . _pendingForceUpdate = false ;
var markup ;
if ( inst . unstable _handleError ) {
markup = this . performInitialMountWithErrorHandling ( renderedElement , hostParent , hostContainerInfo , transaction , context ) ;
} else {
markup = this . performInitialMount ( renderedElement , hostParent , hostContainerInfo , transaction , context ) ;
}
if ( inst . componentDidMount ) {
if ( process . env . NODE _ENV !== 'production' ) {
transaction . getReactMountReady ( ) . enqueue ( function ( ) {
measureLifeCyclePerf ( function ( ) {
return inst . componentDidMount ( ) ;
} , _this . _debugID , 'componentDidMount' ) ;
} ) ;
} else {
transaction . getReactMountReady ( ) . enqueue ( inst . componentDidMount , inst ) ;
}
}
return markup ;
} ,
_constructComponent : function ( doConstruct , publicProps , publicContext , updateQueue ) {
if ( process . env . NODE _ENV !== 'production' ) {
ReactCurrentOwner . current = this ;
try {
return this . _constructComponentWithoutOwner ( doConstruct , publicProps , publicContext , updateQueue ) ;
} finally {
ReactCurrentOwner . current = null ;
}
} else {
return this . _constructComponentWithoutOwner ( doConstruct , publicProps , publicContext , updateQueue ) ;
}
} ,
_constructComponentWithoutOwner : function ( doConstruct , publicProps , publicContext , updateQueue ) {
var Component = this . _currentElement . type ;
if ( doConstruct ) {
if ( process . env . NODE _ENV !== 'production' ) {
return measureLifeCyclePerf ( function ( ) {
return new Component ( publicProps , publicContext , updateQueue ) ;
} , this . _debugID , 'ctor' ) ;
} else {
return new Component ( publicProps , publicContext , updateQueue ) ;
}
}
// This can still be an instance in case of factory components
// but we'll count this as time spent rendering as the more common case.
if ( process . env . NODE _ENV !== 'production' ) {
return measureLifeCyclePerf ( function ( ) {
return Component ( publicProps , publicContext , updateQueue ) ;
} , this . _debugID , 'render' ) ;
} else {
return Component ( publicProps , publicContext , updateQueue ) ;
}
} ,
performInitialMountWithErrorHandling : function ( renderedElement , hostParent , hostContainerInfo , transaction , context ) {
var markup ;
var checkpoint = transaction . checkpoint ( ) ;
try {
markup = this . performInitialMount ( renderedElement , hostParent , hostContainerInfo , transaction , context ) ;
} catch ( e ) {
// Roll back to checkpoint, handle error (which may add items to the transaction), and take a new checkpoint
transaction . rollback ( checkpoint ) ;
this . _instance . unstable _handleError ( e ) ;
if ( this . _pendingStateQueue ) {
this . _instance . state = this . _processPendingState ( this . _instance . props , this . _instance . context ) ;
}
checkpoint = transaction . checkpoint ( ) ;
this . _renderedComponent . unmountComponent ( true ) ;
transaction . rollback ( checkpoint ) ;
// Try again - we've informed the component about the error, so they can render an error message this time.
// If this throws again, the error will bubble up (and can be caught by a higher error boundary).
markup = this . performInitialMount ( renderedElement , hostParent , hostContainerInfo , transaction , context ) ;
}
return markup ;
} ,
performInitialMount : function ( renderedElement , hostParent , hostContainerInfo , transaction , context ) {
var inst = this . _instance ;
var debugID = 0 ;
if ( process . env . NODE _ENV !== 'production' ) {
debugID = this . _debugID ;
}
if ( inst . componentWillMount ) {
if ( process . env . NODE _ENV !== 'production' ) {
measureLifeCyclePerf ( function ( ) {
return inst . componentWillMount ( ) ;
} , debugID , 'componentWillMount' ) ;
} else {
inst . componentWillMount ( ) ;
}
// When mounting, calls to `setState` by `componentWillMount` will set
// `this._pendingStateQueue` without triggering a re-render.
if ( this . _pendingStateQueue ) {
inst . state = this . _processPendingState ( inst . props , inst . context ) ;
}
}
// If not a stateless component, we now render
if ( renderedElement === undefined ) {
renderedElement = this . _renderValidatedComponent ( ) ;
}
var nodeType = ReactNodeTypes . getType ( renderedElement ) ;
this . _renderedNodeType = nodeType ;
var child = this . _instantiateReactComponent ( renderedElement , nodeType !== ReactNodeTypes . EMPTY /* shouldHaveDebugID */
) ;
this . _renderedComponent = child ;
var markup = ReactReconciler . mountComponent ( child , transaction , hostParent , hostContainerInfo , this . _processChildContext ( context ) , debugID ) ;
if ( process . env . NODE _ENV !== 'production' ) {
if ( debugID !== 0 ) {
var childDebugIDs = child . _debugID !== 0 ? [ child . _debugID ] : [ ] ;
ReactInstrumentation . debugTool . onSetChildren ( debugID , childDebugIDs ) ;
}
}
return markup ;
} ,
getHostNode : function ( ) {
return ReactReconciler . getHostNode ( this . _renderedComponent ) ;
} ,
/ * *
* Releases any resources allocated by ` mountComponent ` .
*
* @ final
* @ internal
* /
unmountComponent : function ( safely ) {
if ( ! this . _renderedComponent ) {
return ;
}
var inst = this . _instance ;
if ( inst . componentWillUnmount && ! inst . _calledComponentWillUnmount ) {
inst . _calledComponentWillUnmount = true ;
if ( safely ) {
var name = this . getName ( ) + '.componentWillUnmount()' ;
ReactErrorUtils . invokeGuardedCallback ( name , inst . componentWillUnmount . bind ( inst ) ) ;
} else {
if ( process . env . NODE _ENV !== 'production' ) {
measureLifeCyclePerf ( function ( ) {
return inst . componentWillUnmount ( ) ;
} , this . _debugID , 'componentWillUnmount' ) ;
} else {
inst . componentWillUnmount ( ) ;
}
}
}
if ( this . _renderedComponent ) {
ReactReconciler . unmountComponent ( this . _renderedComponent , safely ) ;
this . _renderedNodeType = null ;
this . _renderedComponent = null ;
this . _instance = null ;
}
// Reset pending fields
// Even if this component is scheduled for another update in ReactUpdates,
// it would still be ignored because these fields are reset.
this . _pendingStateQueue = null ;
this . _pendingReplaceState = false ;
this . _pendingForceUpdate = false ;
this . _pendingCallbacks = null ;
this . _pendingElement = null ;
// These fields do not really need to be reset since this object is no
// longer accessible.
this . _context = null ;
this . _rootNodeID = 0 ;
this . _topLevelWrapper = null ;
// Delete the reference from the instance to this internal representation
// which allow the internals to be properly cleaned up even if the user
// leaks a reference to the public instance.
ReactInstanceMap . remove ( inst ) ;
// Some existing components rely on inst.props even after they've been
// destroyed (in event handlers).
// TODO: inst.props = null;
// TODO: inst.state = null;
// TODO: inst.context = null;
} ,
/ * *
* Filters the context object to only contain keys specified in
* ` contextTypes `
*
* @ param { object } context
* @ return { ? object }
* @ private
* /
_maskContext : function ( context ) {
var Component = this . _currentElement . type ;
var contextTypes = Component . contextTypes ;
if ( ! contextTypes ) {
return emptyObject ;
}
var maskedContext = { } ;
for ( var contextName in contextTypes ) {
maskedContext [ contextName ] = context [ contextName ] ;
}
return maskedContext ;
} ,
/ * *
* Filters the context object to only contain keys specified in
* ` contextTypes ` , and asserts that they are valid .
*
* @ param { object } context
* @ return { ? object }
* @ private
* /
_processContext : function ( context ) {
var maskedContext = this . _maskContext ( context ) ;
if ( process . env . NODE _ENV !== 'production' ) {
var Component = this . _currentElement . type ;
if ( Component . contextTypes ) {
this . _checkContextTypes ( Component . contextTypes , maskedContext , 'context' ) ;
}
}
return maskedContext ;
} ,
/ * *
* @ param { object } currentContext
* @ return { object }
* @ private
* /
_processChildContext : function ( currentContext ) {
var Component = this . _currentElement . type ;
var inst = this . _instance ;
var childContext ;
if ( inst . getChildContext ) {
if ( process . env . NODE _ENV !== 'production' ) {
ReactInstrumentation . debugTool . onBeginProcessingChildContext ( ) ;
try {
childContext = inst . getChildContext ( ) ;
} finally {
ReactInstrumentation . debugTool . onEndProcessingChildContext ( ) ;
}
} else {
childContext = inst . getChildContext ( ) ;
}
}
if ( childContext ) {
! ( typeof Component . childContextTypes === 'object' ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().' , this . getName ( ) || 'ReactCompositeComponent' ) : _prodInvariant ( '107' , this . getName ( ) || 'ReactCompositeComponent' ) : void 0 ;
if ( process . env . NODE _ENV !== 'production' ) {
this . _checkContextTypes ( Component . childContextTypes , childContext , 'child context' ) ;
}
for ( var name in childContext ) {
! ( name in Component . childContextTypes ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s.getChildContext(): key "%s" is not defined in childContextTypes.' , this . getName ( ) || 'ReactCompositeComponent' , name ) : _prodInvariant ( '108' , this . getName ( ) || 'ReactCompositeComponent' , name ) : void 0 ;
}
return _assign ( { } , currentContext , childContext ) ;
}
return currentContext ;
} ,
/ * *
* Assert that the context types are valid
*
* @ param { object } typeSpecs Map of context field to a ReactPropType
* @ param { object } values Runtime values that need to be type - checked
* @ param { string } location e . g . "prop" , "context" , "child context"
* @ private
* /
_checkContextTypes : function ( typeSpecs , values , location ) {
if ( process . env . NODE _ENV !== 'production' ) {
checkReactTypeSpec ( typeSpecs , values , location , this . getName ( ) , null , this . _debugID ) ;
}
} ,
receiveComponent : function ( nextElement , transaction , nextContext ) {
var prevElement = this . _currentElement ;
var prevContext = this . _context ;
this . _pendingElement = null ;
this . updateComponent ( transaction , prevElement , nextElement , prevContext , nextContext ) ;
} ,
/ * *
* If any of ` _pendingElement ` , ` _pendingStateQueue ` , or ` _pendingForceUpdate `
* is set , update the component .
*
* @ param { ReactReconcileTransaction } transaction
* @ internal
* /
performUpdateIfNecessary : function ( transaction ) {
if ( this . _pendingElement != null ) {
ReactReconciler . receiveComponent ( this , this . _pendingElement , transaction , this . _context ) ;
} else if ( this . _pendingStateQueue !== null || this . _pendingForceUpdate ) {
this . updateComponent ( transaction , this . _currentElement , this . _currentElement , this . _context , this . _context ) ;
} else {
this . _updateBatchNumber = null ;
}
} ,
/ * *
* Perform an update to a mounted component . The componentWillReceiveProps and
* shouldComponentUpdate methods are called , then ( assuming the update isn ' t
* skipped ) the remaining update lifecycle methods are called and the DOM
* representation is updated .
*
* By default , this implements React ' s rendering and reconciliation algorithm .
* Sophisticated clients may wish to override this .
*
* @ param { ReactReconcileTransaction } transaction
* @ param { ReactElement } prevParentElement
* @ param { ReactElement } nextParentElement
* @ internal
* @ overridable
* /
updateComponent : function ( transaction , prevParentElement , nextParentElement , prevUnmaskedContext , nextUnmaskedContext ) {
var inst = this . _instance ;
! ( inst != null ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , 'Attempted to update component `%s` that has already been unmounted (or failed to mount).' , this . getName ( ) || 'ReactCompositeComponent' ) : _prodInvariant ( '136' , this . getName ( ) || 'ReactCompositeComponent' ) : void 0 ;
var willReceive = false ;
var nextContext ;
// Determine if the context has changed or not
if ( this . _context === nextUnmaskedContext ) {
nextContext = inst . context ;
} else {
nextContext = this . _processContext ( nextUnmaskedContext ) ;
willReceive = true ;
}
var prevProps = prevParentElement . props ;
var nextProps = nextParentElement . props ;
// Not a simple state update but a props update
if ( prevParentElement !== nextParentElement ) {
willReceive = true ;
}
// An update here will schedule an update but immediately set
// _pendingStateQueue which will ensure that any state updates gets
// immediately reconciled instead of waiting for the next batch.
if ( willReceive && inst . componentWillReceiveProps ) {
if ( process . env . NODE _ENV !== 'production' ) {
measureLifeCyclePerf ( function ( ) {
return inst . componentWillReceiveProps ( nextProps , nextContext ) ;
} , this . _debugID , 'componentWillReceiveProps' ) ;
} else {
inst . componentWillReceiveProps ( nextProps , nextContext ) ;
}
}
var nextState = this . _processPendingState ( nextProps , nextContext ) ;
var shouldUpdate = true ;
if ( ! this . _pendingForceUpdate ) {
if ( inst . shouldComponentUpdate ) {
if ( process . env . NODE _ENV !== 'production' ) {
shouldUpdate = measureLifeCyclePerf ( function ( ) {
return inst . shouldComponentUpdate ( nextProps , nextState , nextContext ) ;
} , this . _debugID , 'shouldComponentUpdate' ) ;
} else {
shouldUpdate = inst . shouldComponentUpdate ( nextProps , nextState , nextContext ) ;
}
} else {
if ( this . _compositeType === CompositeTypes . PureClass ) {
shouldUpdate = ! shallowEqual ( prevProps , nextProps ) || ! shallowEqual ( inst . state , nextState ) ;
}
}
}
if ( process . env . NODE _ENV !== 'production' ) {
process . env . NODE _ENV !== 'production' ? warning ( shouldUpdate !== undefined , '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.' , this . getName ( ) || 'ReactCompositeComponent' ) : void 0 ;
}
this . _updateBatchNumber = null ;
if ( shouldUpdate ) {
this . _pendingForceUpdate = false ;
// Will set `this.props`, `this.state` and `this.context`.
this . _performComponentUpdate ( nextParentElement , nextProps , nextState , nextContext , transaction , nextUnmaskedContext ) ;
} else {
// 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 ;
}
} ,
_processPendingState : function ( props , context ) {
var inst = this . _instance ;
var queue = this . _pendingStateQueue ;
var replace = this . _pendingReplaceState ;
this . _pendingReplaceState = false ;
this . _pendingStateQueue = null ;
if ( ! queue ) {
return inst . state ;
}
if ( replace && queue . length === 1 ) {
return queue [ 0 ] ;
}
var nextState = _assign ( { } , replace ? queue [ 0 ] : inst . state ) ;
for ( var i = replace ? 1 : 0 ; i < queue . length ; i ++ ) {
var partial = queue [ i ] ;
_assign ( nextState , typeof partial === 'function' ? partial . call ( inst , nextState , props , context ) : partial ) ;
}
return nextState ;
} ,
/ * *
* Merges new props and state , notifies delegate methods of update and
* performs update .
*
* @ param { ReactElement } nextElement Next element
* @ param { object } nextProps Next public object to set as properties .
* @ param { ? object } nextState Next object to set as state .
* @ param { ? object } nextContext Next public object to set as context .
* @ param { ReactReconcileTransaction } transaction
* @ param { ? object } unmaskedContext
* @ private
* /
_performComponentUpdate : function ( nextElement , nextProps , nextState , nextContext , transaction , unmaskedContext ) {
var _this2 = this ;
var inst = this . _instance ;
var hasComponentDidUpdate = Boolean ( inst . componentDidUpdate ) ;
var prevProps ;
var prevState ;
var prevContext ;
if ( hasComponentDidUpdate ) {
prevProps = inst . props ;
prevState = inst . state ;
prevContext = inst . context ;
}
if ( inst . componentWillUpdate ) {
if ( process . env . NODE _ENV !== 'production' ) {
measureLifeCyclePerf ( function ( ) {
return inst . componentWillUpdate ( nextProps , nextState , nextContext ) ;
} , this . _debugID , 'componentWillUpdate' ) ;
} else {
inst . componentWillUpdate ( nextProps , nextState , nextContext ) ;
}
}
this . _currentElement = nextElement ;
this . _context = unmaskedContext ;
inst . props = nextProps ;
inst . state = nextState ;
inst . context = nextContext ;
this . _updateRenderedComponent ( transaction , unmaskedContext ) ;
if ( hasComponentDidUpdate ) {
if ( process . env . NODE _ENV !== 'production' ) {
transaction . getReactMountReady ( ) . enqueue ( function ( ) {
measureLifeCyclePerf ( inst . componentDidUpdate . bind ( inst , prevProps , prevState , prevContext ) , _this2 . _debugID , 'componentDidUpdate' ) ;
} ) ;
} else {
transaction . getReactMountReady ( ) . enqueue ( inst . componentDidUpdate . bind ( inst , prevProps , prevState , prevContext ) , inst ) ;
}
}
} ,
/ * *
* Call the component ' s ` render ` method and update the DOM accordingly .
*
* @ param { ReactReconcileTransaction } transaction
* @ internal
* /
_updateRenderedComponent : function ( transaction , context ) {
var prevComponentInstance = this . _renderedComponent ;
var prevRenderedElement = prevComponentInstance . _currentElement ;
var nextRenderedElement = this . _renderValidatedComponent ( ) ;
var debugID = 0 ;
if ( process . env . NODE _ENV !== 'production' ) {
debugID = this . _debugID ;
}
if ( shouldUpdateReactComponent ( prevRenderedElement , nextRenderedElement ) ) {
ReactReconciler . receiveComponent ( prevComponentInstance , nextRenderedElement , transaction , this . _processChildContext ( context ) ) ;
} else {
var oldHostNode = ReactReconciler . getHostNode ( prevComponentInstance ) ;
ReactReconciler . unmountComponent ( prevComponentInstance , false ) ;
var nodeType = ReactNodeTypes . getType ( nextRenderedElement ) ;
this . _renderedNodeType = nodeType ;
var child = this . _instantiateReactComponent ( nextRenderedElement , nodeType !== ReactNodeTypes . EMPTY /* shouldHaveDebugID */
) ;
this . _renderedComponent = child ;
var nextMarkup = ReactReconciler . mountComponent ( child , transaction , this . _hostParent , this . _hostContainerInfo , this . _processChildContext ( context ) , debugID ) ;
if ( process . env . NODE _ENV !== 'production' ) {
if ( debugID !== 0 ) {
var childDebugIDs = child . _debugID !== 0 ? [ child . _debugID ] : [ ] ;
ReactInstrumentation . debugTool . onSetChildren ( debugID , childDebugIDs ) ;
}
}
this . _replaceNodeWithMarkup ( oldHostNode , nextMarkup , prevComponentInstance ) ;
}
} ,
/ * *
* Overridden in shallow rendering .
*
* @ protected
* /
_replaceNodeWithMarkup : function ( oldHostNode , nextMarkup , prevInstance ) {
ReactComponentEnvironment . replaceNodeWithMarkup ( oldHostNode , nextMarkup , prevInstance ) ;
} ,
/ * *
* @ protected
* /
_renderValidatedComponentWithoutOwnerOrContext : function ( ) {
var inst = this . _instance ;
var renderedElement ;
if ( process . env . NODE _ENV !== 'production' ) {
renderedElement = measureLifeCyclePerf ( function ( ) {
return inst . render ( ) ;
} , this . _debugID , 'render' ) ;
} else {
renderedElement = inst . render ( ) ;
}
if ( process . env . NODE _ENV !== 'production' ) {
// We allow auto-mocks to proceed as if they're returning null.
if ( renderedElement === undefined && inst . render . _isMockFunction ) {
// This is probably bad practice. Consider warning here and
// deprecating this convenience.
renderedElement = null ;
}
}
return renderedElement ;
} ,
/ * *
* @ private
* /
_renderValidatedComponent : function ( ) {
var renderedElement ;
if ( process . env . NODE _ENV !== 'production' || this . _compositeType !== CompositeTypes . StatelessFunctional ) {
ReactCurrentOwner . current = this ;
try {
renderedElement = this . _renderValidatedComponentWithoutOwnerOrContext ( ) ;
} finally {
ReactCurrentOwner . current = null ;
}
} else {
renderedElement = this . _renderValidatedComponentWithoutOwnerOrContext ( ) ;
}
! (
// TODO: An `isValidNode` function would probably be more appropriate
renderedElement === null || renderedElement === false || React . isValidElement ( renderedElement ) ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.' , this . getName ( ) || 'ReactCompositeComponent' ) : _prodInvariant ( '109' , this . getName ( ) || 'ReactCompositeComponent' ) : void 0 ;
return renderedElement ;
} ,
/ * *
* Lazily allocates the refs object and stores ` component ` as ` ref ` .
*
* @ param { string } ref Reference name .
* @ param { component } component Component to store as ` ref ` .
* @ final
* @ private
* /
attachRef : function ( ref , component ) {
var inst = this . getPublicInstance ( ) ;
! ( inst != null ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , 'Stateless function components cannot have refs.' ) : _prodInvariant ( '110' ) : void 0 ;
var publicComponentInstance = component . getPublicInstance ( ) ;
if ( process . env . NODE _ENV !== 'production' ) {
var componentName = component && component . getName ? component . getName ( ) : 'a component' ;
process . env . NODE _ENV !== 'production' ? warning ( publicComponentInstance != null || component . _compositeType !== CompositeTypes . StatelessFunctional , 'Stateless function components cannot be given refs ' + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.' , ref , componentName , this . getName ( ) ) : void 0 ;
}
var refs = inst . refs === emptyObject ? inst . refs = { } : inst . refs ;
refs [ ref ] = publicComponentInstance ;
} ,
/ * *
* Detaches a reference name .
*
* @ param { string } ref Name to dereference .
* @ final
* @ private
* /
detachRef : function ( ref ) {
var refs = this . getPublicInstance ( ) . refs ;
delete refs [ ref ] ;
} ,
/ * *
* Get a text description of the component that can be used to identify it
* in error messages .
* @ return { string } The name or null .
* @ internal
* /
getName : function ( ) {
var type = this . _currentElement . type ;
var constructor = this . _instance && this . _instance . constructor ;
return type . displayName || constructor && constructor . displayName || type . name || constructor && constructor . name || null ;
} ,
/ * *
* Get the publicly accessible representation of this component - i . e . what
* is exposed by refs and returned by render . Can be null for stateless
* components .
*
* @ return { ReactComponent } the public component instance .
* @ internal
* /
getPublicInstance : function ( ) {
var inst = this . _instance ;
if ( this . _compositeType === CompositeTypes . StatelessFunctional ) {
return null ;
}
return inst ;
} ,
// Stub
_instantiateReactComponent : null
} ;
module . exports = ReactCompositeComponent ;