2017-05-03 15:35:00 +02:00
/ * *
* Copyright 2015 - 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' ) ;
var ReactCurrentOwner = require ( 'react/lib/ReactCurrentOwner' ) ;
var ReactInstanceMap = require ( './ReactInstanceMap' ) ;
var ReactInstrumentation = require ( './ReactInstrumentation' ) ;
var ReactUpdates = require ( './ReactUpdates' ) ;
var invariant = require ( 'fbjs/lib/invariant' ) ;
var warning = require ( 'fbjs/lib/warning' ) ;
function enqueueUpdate ( internalInstance ) {
ReactUpdates . enqueueUpdate ( internalInstance ) ;
}
function formatUnexpectedArgument ( arg ) {
var type = typeof arg ;
if ( type !== 'object' ) {
return type ;
}
var displayName = arg . constructor && arg . constructor . name || type ;
var keys = Object . keys ( arg ) ;
if ( keys . length > 0 && keys . length < 20 ) {
return displayName + ' (keys: ' + keys . join ( ', ' ) + ')' ;
}
return displayName ;
}
function getInternalInstanceReadyForUpdate ( publicInstance , callerName ) {
var internalInstance = ReactInstanceMap . get ( publicInstance ) ;
if ( ! internalInstance ) {
if ( process . env . NODE _ENV !== 'production' ) {
var ctor = publicInstance . constructor ;
// Only warn when we have a callerName. Otherwise we should be silent.
// We're probably calling from enqueueCallback. We don't want to warn
// there because we already warned for the corresponding lifecycle method.
process . env . NODE _ENV !== 'production' ? warning ( ! callerName , '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op. Please check the code for the %s component.' , callerName , callerName , ctor && ( ctor . displayName || ctor . name ) || 'ReactClass' ) : void 0 ;
}
return null ;
}
if ( process . env . NODE _ENV !== 'production' ) {
2017-08-14 05:01:11 +02:00
process . env . NODE _ENV !== 'production' ? warning ( ReactCurrentOwner . current == null , '%s(...): Cannot update during an existing state transition (such as ' + "within `render` or another component's constructor). Render methods " + 'should be a pure function of props and state; constructor ' + 'side-effects are an anti-pattern, but can be moved to ' + '`componentWillMount`.' , callerName ) : void 0 ;
2017-05-03 15:35:00 +02:00
}
return internalInstance ;
}
/ * *
* ReactUpdateQueue allows for state updates to be scheduled into a later
* reconciliation step .
* /
var ReactUpdateQueue = {
/ * *
* Checks whether or not this composite component is mounted .
* @ param { ReactClass } publicInstance The instance we want to test .
* @ return { boolean } True if mounted , false otherwise .
* @ protected
* @ final
* /
isMounted : function ( publicInstance ) {
if ( process . env . NODE _ENV !== 'production' ) {
var owner = ReactCurrentOwner . current ;
if ( owner !== null ) {
process . env . NODE _ENV !== 'production' ? warning ( owner . _warnedAboutRefsInRender , '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.' , owner . getName ( ) || 'A component' ) : void 0 ;
owner . _warnedAboutRefsInRender = true ;
}
}
var internalInstance = ReactInstanceMap . get ( publicInstance ) ;
if ( internalInstance ) {
// During componentWillMount and render this will still be null but after
// that will always render to something. At least for now. So we can use
// this hack.
return ! ! internalInstance . _renderedComponent ;
} else {
return false ;
}
} ,
/ * *
* Enqueue a callback that will be executed after all the pending updates
* have processed .
*
* @ param { ReactClass } publicInstance The instance to use as ` this ` context .
* @ param { ? function } callback Called after state is updated .
* @ param { string } callerName Name of the calling function in the public API .
* @ internal
* /
enqueueCallback : function ( publicInstance , callback , callerName ) {
ReactUpdateQueue . validateCallback ( callback , callerName ) ;
var internalInstance = getInternalInstanceReadyForUpdate ( publicInstance ) ;
// Previously we would throw an error if we didn't have an internal
// instance. Since we want to make it a no-op instead, we mirror the same
// behavior we have in other enqueue* methods.
// We also need to ignore callbacks in componentWillMount. See
// enqueueUpdates.
if ( ! internalInstance ) {
return null ;
}
if ( internalInstance . _pendingCallbacks ) {
internalInstance . _pendingCallbacks . push ( callback ) ;
} else {
internalInstance . _pendingCallbacks = [ callback ] ;
}
// TODO: The callback here is ignored when setState is called from
// componentWillMount. Either fix it or disallow doing so completely in
// favor of getInitialState. Alternatively, we can disallow
// componentWillMount during server-side rendering.
enqueueUpdate ( internalInstance ) ;
} ,
enqueueCallbackInternal : function ( internalInstance , callback ) {
if ( internalInstance . _pendingCallbacks ) {
internalInstance . _pendingCallbacks . push ( callback ) ;
} else {
internalInstance . _pendingCallbacks = [ callback ] ;
}
enqueueUpdate ( internalInstance ) ;
} ,
/ * *
* Forces an update . This should only be invoked when it is known with
* certainty that we are * * not * * in a DOM transaction .
*
* You may want to call this when you know that some deeper aspect of the
* component ' s state has changed but ` setState ` was not called .
*
* This will not invoke ` shouldComponentUpdate ` , but it will invoke
* ` componentWillUpdate ` and ` componentDidUpdate ` .
*
* @ param { ReactClass } publicInstance The instance that should rerender .
* @ internal
* /
enqueueForceUpdate : function ( publicInstance ) {
var internalInstance = getInternalInstanceReadyForUpdate ( publicInstance , 'forceUpdate' ) ;
if ( ! internalInstance ) {
return ;
}
internalInstance . _pendingForceUpdate = true ;
enqueueUpdate ( internalInstance ) ;
} ,
/ * *
* Replaces all of the state . Always use this or ` setState ` to mutate state .
* You should treat ` this.state ` as immutable .
*
* There is no guarantee that ` this.state ` will be immediately updated , so
* accessing ` this.state ` after calling this method may return the old value .
*
* @ param { ReactClass } publicInstance The instance that should rerender .
* @ param { object } completeState Next state .
* @ internal
* /
enqueueReplaceState : function ( publicInstance , completeState , callback ) {
var internalInstance = getInternalInstanceReadyForUpdate ( publicInstance , 'replaceState' ) ;
if ( ! internalInstance ) {
return ;
}
internalInstance . _pendingStateQueue = [ completeState ] ;
internalInstance . _pendingReplaceState = true ;
// Future-proof 15.5
if ( callback !== undefined && callback !== null ) {
ReactUpdateQueue . validateCallback ( callback , 'replaceState' ) ;
if ( internalInstance . _pendingCallbacks ) {
internalInstance . _pendingCallbacks . push ( callback ) ;
} else {
internalInstance . _pendingCallbacks = [ callback ] ;
}
}
enqueueUpdate ( internalInstance ) ;
} ,
/ * *
* Sets a subset of the state . This only exists because _pendingState is
* internal . This provides a merging strategy that is not available to deep
* properties which is confusing . TODO : Expose pendingState or don ' t use it
* during the merge .
*
* @ param { ReactClass } publicInstance The instance that should rerender .
* @ param { object } partialState Next partial state to be merged with state .
* @ internal
* /
enqueueSetState : function ( publicInstance , partialState ) {
if ( process . env . NODE _ENV !== 'production' ) {
ReactInstrumentation . debugTool . onSetState ( ) ;
process . env . NODE _ENV !== 'production' ? warning ( partialState != null , 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().' ) : void 0 ;
}
var internalInstance = getInternalInstanceReadyForUpdate ( publicInstance , 'setState' ) ;
if ( ! internalInstance ) {
return ;
}
var queue = internalInstance . _pendingStateQueue || ( internalInstance . _pendingStateQueue = [ ] ) ;
queue . push ( partialState ) ;
enqueueUpdate ( internalInstance ) ;
} ,
enqueueElementInternal : function ( internalInstance , nextElement , nextContext ) {
internalInstance . _pendingElement = nextElement ;
// TODO: introduce _pendingContext instead of setting it directly.
internalInstance . _context = nextContext ;
enqueueUpdate ( internalInstance ) ;
} ,
validateCallback : function ( callback , callerName ) {
! ( ! callback || typeof callback === 'function' ) ? process . env . NODE _ENV !== 'production' ? invariant ( false , '%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.' , callerName , formatUnexpectedArgument ( callback ) ) : _prodInvariant ( '122' , callerName , formatUnexpectedArgument ( callback ) ) : void 0 ;
}
} ;
module . exports = ReactUpdateQueue ;