内容简介:组件的生命周期分为二个部分在上一章对于组件的挂载已经做了详细的说明,但是涉及到组件生命周期部分被略过.接下来我将详细的对其说明. 组件的挂载涉及到二个比较重要的生命周期方法对于
组件的生命周期分为二个部分
- 组件的挂载
- 组件的更新
组件的挂载
在上一章对于组件的挂载已经做了详细的说明,但是涉及到组件生命周期部分被略过.接下来我将详细的对其说明. 组件的挂载涉及到二个比较重要的生命周期方法 componentWillMount
和 componentDidMount
.
componentWillMount
对于 componentWillMount
这个函数玩过 React
的都知道他是组件 render
之前的触发. 但是如果我再具体点呢. 是在实例之前?还是实例之后?还是构建成真实 dom
之前?还是构建成真实 dom
之前,渲染之前?估计很多人不知道吧.所以在面试的时候无论你对 React
有多熟,还是尽量不要说"精通"二字.(大佬除外)
componentWillMount
是组件更新之前触发,所以直接从 ReactCompositeComponent.mountComponent
里面找
// this.performInitialMount if (inst.componentWillMount) { debugger if ("development" !== "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 ); } } 复制代码
代码在 performInitialMount
函数里面,所以在实例之后,虚拟 dom
构建真实 dom
之前触发的
componentDidMount
直接看代码吧
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 ("development" !== "production") { transaction .getReactMountReady() .enqueue(function() { measureLifeCyclePerf( function() { return inst.componentDidMount(); }, _this._debugID, "componentDidMount" ); }); } else { transaction .getReactMountReady() .enqueue( inst.componentDidMount, inst ); } } 复制代码
它是出现在 markup
(真实dom)之后.但是肯定不会在这里面执行,因为在 markup
还没插入到 container
里面呢。回顾一下上一章的内容 MountComponentIntoNode
方法 mountComponent
之后还有个 setInnerHTML(container, markup)
只有这个函数执行完之后 componentDidMount
才能执行.
注意 performInitialMount
方法
看看下面的代码
class A extends React.Component { render(){ return <K /> } } <App> <A /> </App> 复制代码
this.componentDidMount
的执行顺序是 K-->A--->App
. 因为 APP
执行到 this.performInitialMount
就开始深度遍历了.然后执行 A
, A
又遍历执行 K
. K执行完才向上执行. 了解了他们的执行顺序我们看看
transaction .getReactMountReady() .enqueue(function() { measureLifeCyclePerf( function() { return inst.componentDidMount(); }, _this._debugID, "componentDidMount" ); }); 复制代码
再看看这个 transaction
是在哪里生成的
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( /* useCreateElement */ !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement ); transaction.perform( mountComponentIntoNode, null, componentInstance, container, transaction, shouldReuseMarkup, context ); 复制代码
transaction
是 React
里面一个非常核心的功能. 出现在很多个地方,不搞清楚 transtion
源代码是没办法读下去的.
事务和队列
看看官方给出的流程图
* <pre> * wrappers (injected at creation time) * + + * | | * +-----------------|--------|--------------+ * | v | | * | +---------------+ | | * | +--| wrapper1 |---|----+ | * | | +---------------+ v | | * | | +-------------+ | | * | | +----| wrapper2 |--------+ | * | | | +-------------+ | | | * | | | | | | * | v v v v | wrapper * | +---+ +---+ +---------+ +---+ +---+ | invariants * perform(anyMethod) | | | | | | | | | | | | maintained * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|--------> * | | | | | | | | | | | | * | | | | | | | | | | | | * | | | | | | | | | | | | * | +---+ +---+ +---------+ +---+ +---+ | * | initialize close | * +-----------------------------------------+ * </pre> var TransactionImpl = { reinitializeTransaction: function () { this.transactionWrappers = this.getTransactionWrappers(); if (this.wrapperInitData) { this.wrapperInitData.length = 0; } else { this.wrapperInitData = []; } this._isInTransaction = false; }, _isInTransaction: false, getTransactionWrappers: null, isInTransaction: function () { return !!this._isInTransaction; }, perform: function (method, scope, a, b, c, d, e, f) { !!this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.') : _prodInvariant('27') : void 0; var errorThrown; var ret; try { this._isInTransaction = true; errorThrown = true; this.initializeAll(0); ret = method.call(scope, a, b, c, d, e, f); errorThrown = false; } finally { try { if (errorThrown) { try { this.closeAll(0); } catch (err) {} } else { this.closeAll(0); } } finally { this._isInTransaction = false; } } return ret; }, initializeAll: function (startIndex) { var transactionWrappers = this.transactionWrappers; for (var i = startIndex; i < transactionWrappers.length; i++) { var wrapper = transactionWrappers[i]; try { this.wrapperInitData[i] = OBSERVED_ERROR; this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null; } finally { if (this.wrapperInitData[i] === OBSERVED_ERROR) { try { this.initializeAll(i + 1); } catch (err) {} } } } }, closeAll: function (startIndex) { !this.isInTransaction() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Transaction.closeAll(): Cannot close transaction when none are open.') : _prodInvariant('28') : void 0; var transactionWrappers = this.transactionWrappers; for (var i = startIndex; i < transactionWrappers.length; i++) { var wrapper = transactionWrappers[i]; var initData = this.wrapperInitData[i]; var errorThrown; try { errorThrown = true; if (initData !== OBSERVED_ERROR && wrapper.close) { wrapper.close.call(this, initData); } errorThrown = false; } finally { if (errorThrown) { try { this.closeAll(i + 1); } catch (e) {} } } } this.wrapperInitData.length = 0; } }; module.exports = TransactionImpl; 复制代码
Transaction
的主要作用就是包装一个函数,函数的执行交给 Transaction
,同时Transaction会在函数执行前后执行被注入的 Wrappers
,一个 Wrapper
有二个方法 initialize
和 close
。 Wrapper
是通过 getTransactionWrappers
方法注入的
代码很简单,很容易看明白我就具体说明下每个函数和关键属性的作用
-
perform
执行注入的函数fn
和wrappers
,执行顺序为initializeAll
-->fn
-->closeAll
-
initializeAll
执行所有Wrapper
的initialize
方法 -
closeAll
执行所有Wrapper
的close
方法 -
reinitializeTransaction
初始化 -
isInTransaction
判断事务是否在执行
了解了 Transaction
我们再来仔细分析下上面的代码
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( /* useCreateElement */ !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement ); 复制代码
ReactReconcileTransaction
对 transition
做了一成包装
ReactReconcileTransaction
var TRANSACTION_WRAPPERS = [ SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING ]; if ("development" !== "production") { TRANSACTION_WRAPPERS.push({ initialize: ReactInstrumentation.debugTool.onBeginFlush, close: ReactInstrumentation.debugTool.onEndFlush }); } /** * Currently: * - The order that these are listed in the transaction is critical: * - Suppresses events. * - Restores selection range. * * Future: * - Restore document/overflow scroll positions that were unintentionally * modified via DOM insertions above the top viewport boundary. * - Implement/integrate with customized constraint based layout system and keep * track of which dimensions must be remeasured. * * @class ReactReconcileTransaction */ function ReactReconcileTransaction(useCreateElement) { this.reinitializeTransaction(); this.renderToStaticMarkup = false; this.reactMountReady = CallbackQueue.getPooled( null ); this.useCreateElement = useCreateElement; } var Mixin = { /** * @see Transaction * @abstract * @final * @return {array<object>} List of operation wrap procedures. * TODO: convert to array<TransactionWrapper> */ getTransactionWrappers: function() { return TRANSACTION_WRAPPERS; }, /** * @return {object} The queue to collect `onDOMReady` callbacks with. */ getReactMountReady: function() { return this.reactMountReady; }, /** * @return {object} The queue to collect React async events. */ getUpdateQueue: function() { return ReactUpdateQueue; }, /** * Save current transaction state -- if the return value from this method is * passed to `rollback`, the transaction will be reset to that state. */ checkpoint: function() { // reactMountReady is the our only stateful wrapper return this.reactMountReady.checkpoint(); }, rollback: function(checkpoint) { this.reactMountReady.rollback(checkpoint); }, /** * `PooledClass` looks for this, and will invoke this before allowing this * instance to be reused. */ destructor: function() { CallbackQueue.release(this.reactMountReady); this.reactMountReady = null; } }; 复制代码
getTransactionWrappers
方法里面返回的是 TRANSACTION_WRAPPERS
他的值有4个也就是说注入了四个 Wrapper
。具体看看 ON_DOM_READY_QUEUEING
这个 Wraper
;
var ON_DOM_READY_QUEUEING = { /** * Initializes the internal `onDOMReady` queue. */ initialize: function() { this.reactMountReady.reset(); }, /** * After DOM is flushed, invoke all registered `onDOMReady` callbacks. */ close: function() { this.reactMountReady.notifyAll(); } }; 复制代码
this.reactMountReady
是一个队列, 在组件构建真实 dom
之后
transaction .getReactMountReady() .enqueue(function() { measureLifeCyclePerf( function() { return inst.componentDidMount(); }, _this._debugID, "componentDidMount" ); }); 复制代码
会将 componentDidMount
方法push进入队列里面. 而 mountComponentIntoNode
(插入到了 document
中了)执行完毕之后会执行 ON_DOM_READY_QUEUEING.close
方法也就是 this.reactMountReady.notifyAll()
方法,释放队列中所有的元素。
componentDidMount
是通过一个队列来维护的,因为队列是 先进先出
的.而最里层的组件是最新执行!
以上所述就是小编给大家介绍的《React源代码解析(3):组件的生命周期》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
打火机与公主裙·荒草园
Twentine / 青岛出版社 / 2017-3 / 36.00元
“如果人临死前真有走马灯这个环节,她大概会是我这辈子见的最后一人。” 从青涩的校园时代里一抹明亮的金,到厮杀的职场中那化不开的黑,李峋就像荒芜之地的一株野草,受到再大的挫折依然固执地生长。 如果说朱韵从前的生活一直维持着表面的顺风顺水,平静安和,那李峋的出现则打破了这一切。他是她生命中第一次,也是唯一一次的冒险。 在外人眼里李峋嚣张而轻蔑,只有朱韵懂得他心中那片自留地,自愿成为孤......一起来看看 《打火机与公主裙·荒草园》 这本书的介绍吧!