react版本:
15.6-dev
文件名:
ReactCompositeComponent.js
路徑:
react/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js
github地址:
https://github.com/facebook/react/blob/15.6-dev/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js
源碼(ReactCompositeComponent.js)
'use strict';
var _prodInvariant = require('./reactProdInvariant'),// 生產(chǎn)環(huán)境React形式帶url報錯
_assign = require('object-assign');
var React = require('react/lib/React');
// 提供ReactComponentEnvironment.replaceNodeWithMarkup方法料身,用于替換掛載的Dom元素
var ReactComponentEnvironment = require('./ReactComponentEnvironment');
// 開發(fā)環(huán)境下,ReactClass組件被實(shí)例化或其render方法被調(diào)用時衩茸,向ReactCurrentOwner.current添加當(dāng)前實(shí)例this
// 實(shí)例化完成或render方法執(zhí)行完成芹血,ReactCurrentOwner.current置為null
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
// 調(diào)試用
var ReactErrorUtils = require('./ReactErrorUtils');
// 以對象形式存儲組件實(shí)例
var ReactInstanceMap = require('./ReactInstanceMap');
// 調(diào)試用
var ReactInstrumentation = require('./ReactInstrumentation');
// 用于判斷節(jié)點(diǎn)類型,ReactComponentElement元素返回1;ReactDomElement元素返回0幔烛;若為空啃擦,返回2
var ReactNodeTypes = require('./ReactNodeTypes');
// 用于掛載、移除饿悬、更新組件實(shí)例令蛉,作為方法的發(fā)起者,如ReactReconciler.mountComponent
var ReactReconciler = require('./ReactReconciler');
if (process.env.NODE_ENV !== 'production') {
var checkReactTypeSpec = require('./checkReactTypeSpec');
}
// 空對象狡恬,并且用Object.freeze凍結(jié)為不可修改珠叔、不可擴(kuò)展
var emptyObject = require('fbjs/lib/emptyObject');
// invariant(condition,format,a,b,c,d,e,f) condition為否值,替換format中的"%s"弟劲,并throw error報錯
var invariant = require('fbjs/lib/invariant');
// shallowEqual(A,B)比較值相等祷安,及淺比較鍵值相等
var shallowEqual = require('fbjs/lib/shallowEqual');
// 判斷組件重繪時是采用更新組件實(shí)例的方式(返回真值);還是采用銷毀實(shí)例后兔乞、重新創(chuàng)建實(shí)例的方式(返回否值)
// 組件元素的構(gòu)造函數(shù)或key值不同汇鞭,銷毀實(shí)例后再行創(chuàng)建
var shouldUpdateReactComponent = require('./shouldUpdateReactComponent');
// warning(condition,format) condition為否值,替換format中的"%s"庸追,并console.error警告
var warning = require('fbjs/lib/warning');
// 區(qū)分純函數(shù)無狀態(tài)組件霍骄、PureComponent純組件、Component組件的標(biāo)識符
var CompositeTypes = {
ImpureClass: 0,// 組件淡溯,繼承自React.Component
PureClass: 1,// 純組件读整,繼承自React.PureComponent,不能設(shè)置shouldComponentUpdate方法血筑,重繪時判斷props绘沉、state是否變更
StatelessFunctional: 2// 純函數(shù)無狀態(tài)組件,function(props,context,updateQueue){}形式
};
// 將無狀態(tài)組件function(props,context,updateQueue){}包裝為帶有render原型方法的構(gòu)造函數(shù)形式
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;
};
// 校驗(yàn)無狀態(tài)組件返回值必須是ReactElement豺总,以及不能設(shè)置childContextTypes靜態(tài)屬性
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;
}
}
// 校驗(yàn)是否純組件或組件车伞;返回否值,當(dāng)作非狀態(tài)組件喻喳、或ReactClass的工廠函數(shù)處理
function shouldConstruct(Component) {
return !!(Component.prototype && Component.prototype.isReactComponent);
}
function isPureComponent(Component) {
return !!(Component.prototype && Component.prototype.isPureReactComponent);
}
// 開發(fā)環(huán)境下帶調(diào)試方式執(zhí)行fn
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);
}
}
var nextMountID = 1;
// 自定義組件實(shí)例化另玖、掛載、移除表伦、更新實(shí)現(xiàn)
var ReactCompositeComponent = {
// 實(shí)例化
construct: function (element) {
this._currentElement = element;// ReactComponentElement谦去,配置了組件的構(gòu)造函數(shù)、props屬性等
this._rootNodeID = 0;
this._compositeType = null;// 區(qū)分純函數(shù)無狀態(tài)組件蹦哼、繼承自PureComponent的純組件鳄哭、以及繼承自Component的組件
this._instance = null;// ReactComponent實(shí)例
this._hostParent = null;// 文檔元素,作為組件元素的父節(jié)點(diǎn)
this._hostContainerInfo = null;
// See ReactUpdateQueue
this._updateBatchNumber = null;
this._pendingElement = null;// ReactDom.render方法渲染時包裹元素由react組件渲染纲熏,_pendingElement存儲待渲染元素
this._pendingStateQueue = null;// 組件調(diào)用setState妆丘、replaceState方法锄俄,通過ReactUpdateQueue將更迭后的state推入_pendingStateQueue
this._pendingReplaceState = false;// 判斷組件是否通過調(diào)用replaceState方法向_pendingStateQueue推入state數(shù)據(jù)
this._pendingForceUpdate = false;// 組件調(diào)用forceUpdate賦值為真
this._renderedNodeType = null;// 節(jié)點(diǎn)類型,區(qū)分ReactComponentElement勺拣、ReactDomElement元素
this._renderedComponent = null;// render方法內(nèi)子組件實(shí)例
this._context = null;// 賦值給組件的context屬性
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;
}
},
// 由ReactReconciler.mountComponent方法發(fā)起
// 關(guān)于參數(shù):
// 參數(shù)transaction默認(rèn)為ReactUpdates.ReactReconcileTransaction奶赠,即ReactReconcileTransaction模塊
// 用于在組件元素掛載前后執(zhí)行指定的鉤子函數(shù),選中文本回撤药有、阻止事件觸發(fā)毅戈、生命周期鉤子和調(diào)試等
// 特別是通過執(zhí)行g(shù)etReactMountReady().enqueue()方法,添加componentDidMount愤惰、componentDidUpdate生命周期鉤子
// 其次是通過執(zhí)行g(shù)etUpdateQueue()方法苇经,向組件實(shí)例注入updater參數(shù),默認(rèn)是ReactUpdateQueue模塊
// 意義是為組件的setState羊苟、replaceState塑陵、forceUpdate方法完成功能提供必要的函數(shù)
// 參數(shù)context或者為空對象感憾,或者由上層組件提供蜡励,后者混合this.context和this.getChildContext()形成
// 完成組件實(shí)例化,執(zhí)行實(shí)例的render方法阻桅,通過ReactDomComponent繪制DomLazyTree凉倚,掛載componentDidMount函數(shù)
mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
var _this = this;
this._context = context;
this._mountOrder = nextMountID++;
this._hostParent = hostParent;
this._hostContainerInfo = hostContainerInfo;
// 添加到ReactComponentElement元素的props屬性
var publicProps = this._currentElement.props;
// 通過Component.contextTypes過濾由上層組件注入的context屬性,并做校驗(yàn)
var publicContext = this._processContext(context);
// 純函數(shù)無狀態(tài)組件嫂沉、或者繼承自PureComponent的純組件構(gòu)造函數(shù)稽寒、或者繼承自Component的組件構(gòu)造函數(shù)
var Component = this._currentElement.type;
// 傳入組件ReactComponent的第三個參數(shù)updater,默認(rèn)是ReactUpdateQueue模塊趟章,用于實(shí)現(xiàn)setState等方法
var updateQueue = transaction.getUpdateQueue();
// 校驗(yàn)是否純組件或組件杏糙;返回否值,當(dāng)作非狀態(tài)組件蚓土、或ReactClass的工廠函數(shù)處理
var doConstruct = shouldConstruct(Component);
// 創(chuàng)建純組件或組件實(shí)例宏侍,或者獲取無狀態(tài)組件的返回值
var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue);
// 待掛載的ReactComponentElement元素
var renderedElement;
// Component為純函數(shù)無狀態(tài)組件書寫方式
if (!doConstruct && (inst == null || inst.render == null)) {
// 無狀態(tài)組件返回值即是待掛載的ReactElement
renderedElement = inst;
// 校驗(yàn)無狀態(tài)組件返回值必須是ReactElement,以及不能設(shè)置childContextTypes靜態(tài)屬性
warnIfInvalidElement(Component, renderedElement);
// 校驗(yàn)無狀態(tài)組件的返回值是否ReactElement
!(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;
// 將無狀態(tài)組件function(props,context,updateQueue){}包裝為帶有render原型方法的構(gòu)造函數(shù)形式
inst = new StatelessComponent(Component);
// 添加無狀態(tài)組件標(biāo)識
this._compositeType = CompositeTypes.StatelessFunctional;
// Component為純組件或組件形式
} else {
if (isPureComponent(Component)) {
// 添加純組件標(biāo)識
this._compositeType = CompositeTypes.PureClass;
} else {
// 添加組件標(biāo)識
this._compositeType = CompositeTypes.ImpureClass;
}
}
// 實(shí)例沒有render方法蜀漆,或者props屬性同publicProps不符谅河,警告
if (process.env.NODE_ENV !== 'production') {
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';
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;
}
// 原本作為構(gòu)造函數(shù)的參數(shù)傳入,為方便起見确丢,再次賦值绷耍,同時保證實(shí)例數(shù)據(jù)的準(zhǔn)確性
inst.props = publicProps;
inst.context = publicContext;
inst.refs = emptyObject;
inst.updater = updateQueue;
this._instance = inst;
// ReactInstanceMap中添加組件實(shí)例
ReactInstanceMap.set(inst, this);
if (process.env.NODE_ENV !== 'production') {
// 組件不是由ReactClass方式創(chuàng)建,且添加了getInitialState或getDefaultProps方法鲜侥,警告
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;
// 靜態(tài)屬性propTypes褂始、contextTypes書寫為原型屬性提示,只構(gòu)造函數(shù)擁有描函,實(shí)例沒有
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;
}
// 獲取初始state崎苗,并提示state只能設(shè)置為對象形式
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;
// 執(zhí)行實(shí)例inst的render方法搂赋,嵌套調(diào)用mountComponent,將返回值ReactNode元素轉(zhuǎn)化成DomLazyTree輸出
var markup;
if (inst.unstable_handleError) {
markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context);
} else {
markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
}
// 向后置鉤子transaction.getReactMountReady()中添加實(shí)例的生命周期方法componentDidMount
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;
},
// 創(chuàng)建純組件或組件實(shí)例益缠,或者獲取無狀態(tài)組件的返回值
_constructComponent: function (doConstruct, publicProps, publicContext, updateQueue) {
if (process.env.NODE_ENV !== 'production') {
ReactCurrentOwner.current = this;
try {
// 創(chuàng)建純組件或組件實(shí)例脑奠,或者獲取無狀態(tài)組件的返回值
return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
} finally {
ReactCurrentOwner.current = null;
}
} else {
return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
}
},
// 創(chuàng)建純組件或組件實(shí)例,或者獲取無狀態(tài)組件的返回值
_constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, updateQueue) {
var Component = this._currentElement.type;
// Component為純組件或組件幅慌,創(chuàng)建實(shí)例宋欺;Component可能為TopLevelWrapper
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);
}
}
// Component為工廠函數(shù)ReactClassFacory=function(props,context,updateQueue){
// return new ReactClass(props,context,updateQueue)
// }
// 或者,無狀態(tài)組件純函數(shù)形式function(props,context,updateQueue){}
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) {
// _processPendingState方法獲取組件setState胰伍、replaceState方法執(zhí)行后的最終state
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;
},
// 執(zhí)行ReactComponent實(shí)例的render方法齿诞,獲取其返回值ReactNode
// 嵌套調(diào)用mountComponent,完成ReactNode元素相應(yīng)組件的實(shí)例化和render方法執(zhí)行
// 最終通過ReactDomElement轉(zhuǎn)化為DOMLazyTree對象輸出骂租,其node屬性為需要插入文檔dom對象
performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) {
var inst = this._instance;
var debugID = 0;
if (process.env.NODE_ENV !== 'production') {
debugID = this._debugID;
}
// 執(zhí)行組件實(shí)例的componentWillMount方法
// componentWillMount方法內(nèi)調(diào)用setState祷杈、replaceState,_pendingStateQueue有值渗饮,刷新state后再行繪制
if (inst.componentWillMount) {
if (process.env.NODE_ENV !== 'production') {
measureLifeCyclePerf(function () {
return inst.componentWillMount();
}, debugID, 'componentWillMount');
} else {
inst.componentWillMount();
}
if (this._pendingStateQueue) {
// _processPendingState方法獲取組件setState但汞、replaceState方法執(zhí)行后的最終state
inst.state = this._processPendingState(inst.props, inst.context);
}
}
// 間接執(zhí)行ReactClass或TopLevelWrapper實(shí)例的render方法,獲取待掛載的元素ReactNode
// 組件若為函數(shù)式無狀態(tài)組件function(props,context,updateQueue){}互站,renderedElement由傳參提供
if (renderedElement === undefined) {
// 調(diào)用組件實(shí)例inst的render方法私蕾,獲取待掛載的元素ReactNode
renderedElement = this._renderValidatedComponent();
}
// 節(jié)點(diǎn)類型,ReactComponentElement元素返回1胡桃;ReactDomElement元素返回0踩叭;若為空,返回2
var nodeType = ReactNodeTypes.getType(renderedElement);
this._renderedNodeType = nodeType;
// 調(diào)用instantiateReactComponent模塊以實(shí)例化render方法的返回值翠胰,即renderedElement元素
var child = this._instantiateReactComponent(renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
);
// render方法內(nèi)子組件實(shí)例
this._renderedComponent = child;
// 嵌套調(diào)用mountComponent容贝,完成renderedElement元素相應(yīng)組件的實(shí)例化及render方法執(zhí)行
// 最終通過ReactDomElement轉(zhuǎn)化為DOMLazyTree對象輸出,其node屬性為需要插入文檔dom對象
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;
},
// 由render方法內(nèi)子組件實(shí)例之景,通過ReactDomComponent等斤富,獲取相應(yīng)的dom節(jié)點(diǎn)
getHostNode: function () {
return ReactReconciler.getHostNode(this._renderedComponent);
},
// 移除組件,執(zhí)行componentWillUnmount方法
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;
}
this._pendingStateQueue = null;
this._pendingReplaceState = false;
this._pendingForceUpdate = false;
this._pendingCallbacks = null;
this._pendingElement = null;
this._context = null;
this._rootNodeID = 0;
this._topLevelWrapper = null;
ReactInstanceMap.remove(inst);
},
// 通過Component.contextTypes過濾由上層組件注入的context屬性闺兢,僅保留Component.contextTypes約定的
_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;
},
// 通過Component.contextTypes過濾由上層組件注入的context屬性茂缚,并做校驗(yàn)
_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;
},
// 將當(dāng)前組件的Context注入子組件;執(zhí)行g(shù)etChildContext方法并作校驗(yàn)屋谭,注入子組件的context中
_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, 'childContext');
}
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;
},
// 校驗(yàn)context
_checkContextTypes: function (typeSpecs, values, location) {
if (process.env.NODE_ENV !== 'production') {
checkReactTypeSpec(typeSpecs, values, location, this.getName(), null, this._debugID);
}
},
// 接受新的組件待渲染元素nextElement脚囊,以替換舊的組件元素this._currentElement
// 通過performUpdateIfNecessary方法調(diào)用,nextElement由this._pendingElement提供
// 該方法觸發(fā)執(zhí)行的實(shí)際情形是ReactDom.render(ReactNode,pNode)掛載的組件元素桐磁,其父節(jié)點(diǎn)pNode由react方式繪制
// 通過_updateRenderedComponent方法調(diào)用悔耘,nextElement為待變更的子組件元素
receiveComponent: function (nextElement, transaction, nextContext) {
var prevElement = this._currentElement;
var prevContext = this._context;
this._pendingElement = null;
this.updateComponent(transaction, prevElement, nextElement, prevContext, nextContext);
},
// 由ReactDom.render(ReactNode,pNode)方法插入文檔時,pNode由react方式繪制
// 調(diào)用ReactReconciler.receiveComponent間接執(zhí)行updateComponent方法重繪組件
// 組件的setState我擂、replaceState衬以、forceUpdate方法觸發(fā)重繪缓艳,直接調(diào)用updateComponent方法重繪組件
performUpdateIfNecessary: function (transaction) {
// ReactDom.render方法渲染時包裹元素由react組件渲染,將待渲染元素推入_pendingElement中
if (this._pendingElement != null) {
ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context);
// 通過調(diào)用組件的setState看峻、replaceState阶淘、forceUpdate方法重繪組件
} else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
} else {
this._updateBatchNumber = null;
}
},
// 判斷props變更情況,執(zhí)行shouldComponentUpdate方法互妓,重繪組件或者更改組件的屬性
// 參數(shù)transaction溪窒,組件重繪時用于向子組件提供updater參數(shù),setState等方法可用冯勉;以及實(shí)現(xiàn)componentWillMount掛載功能
// 參數(shù)prevParentElement變更前的組件元素ReactNode澈蚌,nextParentElement變更后的組件元素,作為render方法渲染節(jié)點(diǎn)的父元素
// 參數(shù)prevUnmaskedContext更迭前的context灼狰,nextUnmaskedContext更迭后的context
updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {
var inst = this._instance;
// 組件實(shí)例尚未生成宛瞄,報錯
!(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;
// 更新context
if (this._context === nextUnmaskedContext) {
nextContext = inst.context;
} else {
nextContext = this._processContext(nextUnmaskedContext);
willReceive = true;
}
var prevProps = prevParentElement.props;
var nextProps = nextParentElement.props;
// 包含僅待渲染元素的props變更
if (prevParentElement !== nextParentElement) {
willReceive = true;
}
// 更新context、或變更帶渲染組件元素或其props時willReceive賦值為真交胚,由父組件發(fā)起份汗,調(diào)用componentWillReceiveProps方法
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);
}
}
// _processPendingState方法獲取組件setState、replaceState方法執(zhí)行后的最終state
var nextState = this._processPendingState(nextProps, nextContext);
var shouldUpdate = true;
// 調(diào)用組件的shouldComponentUpdate判斷是否需要重繪
// 純組件不能設(shè)置shouldComponentUpdate方法承绸,僅判斷props裸影、state是否變更
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);
}
}
}
// shouldComponentUpdate方法返回undefined,警告
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;
// 執(zhí)行componentWillUpdate方法军熏,重繪組件實(shí)例render方法內(nèi)待渲染的子組件,掛載componentDidUpdate方法
this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext);
// 只變更組件的部分屬性卷扮,不開啟重繪功能
} else {
this._currentElement = nextParentElement;
this._context = nextUnmaskedContext;
inst.props = nextProps;
inst.state = nextState;
inst.context = nextContext;
}
},
// 獲取組件setState荡澎、replaceState方法執(zhí)行后的最終state
// setState、replaceState方法執(zhí)行后更迭的state以函數(shù)或state數(shù)據(jù)形式推入_pendingStateQueue中
_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;
},
// 執(zhí)行componentWillUpdate方法晤锹,重繪組件實(shí)例render方法內(nèi)待渲染的子組件摩幔,掛載componentDidUpdate方法
_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;
}
// 執(zhí)行componentWillUpdate方法
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;
// 以更新子組件的方式或重新創(chuàng)建子組件的方式重繪render方法待渲染的子組件
this._updateRenderedComponent(transaction, unmaskedContext);
// 向后置鉤子transaction.getReactMountReady()中添加實(shí)例的生命周期方法componentDidUpdate
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);
}
}
},
// 以更新子組件的方式或重新創(chuàng)建子組件的方式重繪render方法待渲染的子組件
_updateRenderedComponent: function (transaction, context) {
var prevComponentInstance = this._renderedComponent;// 組件render待渲染的子組件實(shí)例
var prevRenderedElement = prevComponentInstance._currentElement;// 子組件元素
// _renderValidatedComponent方法調(diào)用組件實(shí)例inst的render方法,獲取待掛載的元素
var nextRenderedElement = this._renderValidatedComponent();
var debugID = 0;
if (process.env.NODE_ENV !== 'production') {
debugID = this._debugID;
}
// shouldUpdateReactComponent方法返回真值鞭铆,更新組件實(shí)例或衡;返回否值,銷毀實(shí)例后车遂、重新創(chuàng)建實(shí)例
// 組件元素的構(gòu)造函數(shù)或key值不同封断,銷毀實(shí)例后再行創(chuàng)建
// render方法子組件構(gòu)造函數(shù)及key相同,通過ReactReconciler.receiveComponent方法更新子組件實(shí)例
if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context));
// render方法子組件構(gòu)造函數(shù)或key不同舶担,重新創(chuàng)建子組件實(shí)例后坡疼,調(diào)用_replaceNodeWithMarkup方法替換掛載元素
} 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);
}
}
// 替換文檔中掛載的Dom元素DomLazyTree
this._replaceNodeWithMarkup(oldHostNode, nextMarkup, prevComponentInstance);
}
},
// 替換文檔中掛載的Dom元素DomLazyTree
_replaceNodeWithMarkup: function (oldHostNode, nextMarkup, prevInstance) {
ReactComponentEnvironment.replaceNodeWithMarkup(oldHostNode, nextMarkup, prevInstance);
},
// 調(diào)用組件實(shí)例inst的render方法,獲取待掛載的元素
_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') {
if (renderedElement === undefined && inst.render._isMockFunction) {
renderedElement = null;
}
}
return renderedElement;
},
// 調(diào)用組件實(shí)例inst的render方法衣陶,獲取待掛載的元素
_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();
}
// 校驗(yàn)renderedElement是否為ReactElement
!(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;
},
// 對外提供接口柄瑰,用于向組件實(shí)例ReactComponentInstance添加this.refs屬性
attachRef: function (ref, component) {// 參數(shù)component為子組件
var inst = this.getPublicInstance();
// 無狀態(tài)組件沒有this.refs屬性
!(inst != null) ? process.env.NODE_ENV !== 'production' ?
invariant(false, 'Stateless function components cannot have refs.')
: _prodInvariant('110') : void 0;
var publicComponentInstance = component.getPublicInstance();// 子組件的實(shí)例
// 無狀態(tài)子組件也不能作為上層組件的this.refs的值
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;
}
// 通過引用對象的形式賦值inst.refs
var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
refs[ref] = publicComponentInstance;
},
// 銷毀組件實(shí)例ReactComponentInstance的refs屬性
detachRef: function (ref) {
var refs = this.getPublicInstance().refs;
delete refs[ref];
},
// 獲取組件名
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;
},
// 獲取組件ReactComponent的實(shí)例
getPublicInstance: function () {
var inst = this._instance;
if (this._compositeType === CompositeTypes.StatelessFunctional) {
return null;
}
return inst;
},
// 調(diào)用instantiateReactComponent模塊闸氮,用于創(chuàng)建子組件
_instantiateReactComponent: null
};
module.exports = ReactCompositeComponent;