生命周期,Component生命周期

By admin in 4858美高梅 on 2019年3月27日

Preact是React的轻量级完毕,是React相比较好的替代者之一,有着容量小的优点,当然与React之间自然会设有落实上的不相同,本文介绍了在
setState 方面包车型的士差别之处。

Preact是React的轻量级完结,是React比较好的替代者之一,有着体量小的独到之处,当然与React之间自然会设有落到实处上的反差,本文介绍了在
setState 方面包车型大巴差异之处。

生命周期方法


组件的生命周期分为多少个情形:

    • Mounting:已插入真实 DOM
    • Updating:正在被重复渲染
    • Unmounting:已移出真实 DOM

React
为每一个情形都提供了三种处理函数,will 函数在进入状态此前调用,did 函数在进入状态之后调用,二种处境共计两种处理函数。

    • componentWillMount()
    • componentDidMount()
    • componentWillUpdate(object nextProps, object nextState)
    • componentDidUpdate(object prevProps, object prevState)
    • componentWillUnmount()

 

除此以外,React 还提供二种非凡情形的处理函数。

    • component威尔ReceiveProps(object
      nextProps):已加载组件收到新的参数时调用

    • shouldComponentUpdate(object nextProps, object
      nextState):组件判断是还是不是再一次渲染时调用

 

 

参考链接:React Native
中组件的生命周期

源码分析

第叁来分析下React以及Preact在setState部分的切实可行落到实处。

(太长不看想偷懒,能够直接下翻看结论)

源码分析

第叁来分析下React以及Preact在setState部分的切切实实贯彻。

(太长不看想偷懒,能够直接下翻看结论)

挂载:componentWillMount

 

  1. 劳动器端和客户端都只调用三遍,在初叶化渲染执行从前及时调用。
  2. 借使在这些方法内调用 setStaterender() 将会感知到更新后的 state
  3. 用法

    React.createClass({
      componentWillMount() {
        ...
      }
    });
    

     

4858美高梅 1

React

重在代码:

React

注重代码:

挂载: componentDidMount

  1. 在先导化渲染执行之后登时调用一遍,仅客户端有效(服务器端不会调用)
  2. 在生命周期中的这一个时间点,组件拥有叁个 DOM
    显示,你能够通过 this.getDOMNode() 来获取相应 DOM 节点
  3. 出殡 AJAX 请求,能够在该办法中履行那么些操作
  4. 例子

    React.createClass({
      componentDidMount() {
        ...
      }
    });
    

     

生命周期流程图

生命周期,Component生命周期。setState 阶段:

// ReactUpdateQueue.js
enqueueSetState: function(publicInstance, partialState) {
  ...

  var queue =
    internalInstance._pendingStateQueue ||
    (internalInstance._pendingStateQueue = []);
  queue.push(partialState);

  enqueueUpdate(internalInstance);
}

能够观察React在 setState
的时候不会做任何处理,会把改变直接放到二个专程处理 state
的队列里供组件更新时使用。

setState 阶段:

// ReactUpdateQueue.js
enqueueSetState: function(publicInstance, partialState) {
  ...

  var queue =
    internalInstance._pendingStateQueue ||
    (internalInstance._pendingStateQueue = []);
  queue.push(partialState);

  enqueueUpdate(internalInstance);
}

能够见见React在 setState
的时候不会做任何处理,会把改变直接放到三个特意处理 state
的队列里供组件更新时利用。

移除: componentWillUnmount

  1. 在组件从 DOM 中移除的时候立刻被调用
  2. 在该方法中进行其余要求的清理,比如无效的定时器,也许排除在 componentDidMount 中成立的
    DOM 成分
  3. 例子

    React.createClass({
      componentWillUnmount() {
        ...
      }
    });
    

     

如图,可以把组件生命周期差不离分成多个级次:

第3等级:是组件第三次绘制阶段,如图中的上边虚线框内,在此处完毕了组件的加载和起先化,在那之中getDefaultProps,getInitialState
在新版的Component中ES6语法继承时,直接复写方法会报分外,中华VN
API须要大家props,state的发轫化在Component的constructor函数中达成;

其次等级:是组件在运维和交互阶段,如图中左下角虚线框,这些阶段组件可以拍卖用户交互,恐怕吸收事件更新界面;

其三阶段:是组件卸载消亡的等级,如图中右下角的虚线框中,那里做一些组件的清理工科作。

更新阶段:

// ReactCompositeComponent.js
updateComponent: function(
  transaction,
  prevParentElement,
  nextParentElement,
  prevUnmaskedContext,
  nextUnmaskedContext,
) {
  var inst = this._instance;
  ...

  var willReceive = false;
  var nextContext;

  if (this._context === nextUnmaskedContext) {
    nextContext = inst.context;
  } else {
    nextContext = this._processContext(nextUnmaskedContext);
    willReceive = true;
  }

  var prevProps = prevParentElement.props;
  var nextProps = nextParentElement.props;

  if (prevParentElement !== nextParentElement) {
    willReceive = true;
  }

  if (willReceive && inst.componentWillReceiveProps) {
    ...
    inst.componentWillReceiveProps(nextProps, nextContext);
  }

  // 在此处才计算 nextState
  var nextState = this._processPendingState(nextProps, nextContext); // 此处传入了 nextProps
  var shouldUpdate = true;

  if (!this._pendingForceUpdate) {
    if (inst.shouldComponentUpdate) {
      ...
      shouldUpdate = inst.shouldComponentUpdate(
        nextProps,
        nextState,
        nextContext,
      );
    } else {
      if (this._compositeType === CompositeTypes.PureClass) { // 敲黑板,知识点 —— 如果你的组件没实现shouldComponentUpdate,那么把React.Component 换成 React.PureComponent 可以获得基础版优化,提高性能。
        shouldUpdate =
          !shallowEqual(prevProps, nextProps) ||
          !shallowEqual(inst.state, nextState); // 浅比较,可以抄去自己改成属性黑/白名单版
      }
    }
  }
  ...
}

// ReactCompositeComponent.js
_processPendingState: function(props, context) { // props: nextProps
  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 = Object.assign({}, replace ? queue[0] : inst.state);
  for (var i = replace ? 1 : 0; i < queue.length; i++) {
    var partial = queue[i];
    Object.assign(
      nextState,
      typeof partial === 'function'
        ? partial.call(inst, nextState, props, context) // nextProps
        : partial,
    );
  }

  return nextState;
}

通过地点组件更新的流程代码能够见见:

  • 在 updateComponent 中,在 component威尔ReceiveProps 之后才会总计nextState,所以在 componentWillReceiveProps 中 setState
    是足以在当次翻新中生效的。
  • 在 _processPendingState 会对队列里的 state
    进行叠加,借使改动是函数形式,此处传入的state参数是 nextState,props
    是 nextProps。

创新阶段:

// ReactCompositeComponent.js
updateComponent: function(
  transaction,
  prevParentElement,
  nextParentElement,
  prevUnmaskedContext,
  nextUnmaskedContext,
) {
  var inst = this._instance;
  ...

  var willReceive = false;
  var nextContext;

  if (this._context === nextUnmaskedContext) {
    nextContext = inst.context;
  } else {
    nextContext = this._processContext(nextUnmaskedContext);
    willReceive = true;
  }

  var prevProps = prevParentElement.props;
  var nextProps = nextParentElement.props;

  if (prevParentElement !== nextParentElement) {
    willReceive = true;
  }

  if (willReceive && inst.componentWillReceiveProps) {
    ...
    inst.componentWillReceiveProps(nextProps, nextContext);
  }

  // 在此处才计算 nextState
  var nextState = this._processPendingState(nextProps, nextContext); // 此处传入了 nextProps
  var shouldUpdate = true;

  if (!this._pendingForceUpdate) {
    if (inst.shouldComponentUpdate) {
      ...
      shouldUpdate = inst.shouldComponentUpdate(
        nextProps,
        nextState,
        nextContext,
      );
    } else {
      if (this._compositeType === CompositeTypes.PureClass) { // 敲黑板,知识点 —— 如果你的组件没实现shouldComponentUpdate,那么把React.Component 换成 React.PureComponent 可以获得基础版优化,提高性能。
        shouldUpdate =
          !shallowEqual(prevProps, nextProps) ||
          !shallowEqual(inst.state, nextState); // 浅比较,可以抄去自己改成属性黑/白名单版
      }
    }
  }
  ...
}

// ReactCompositeComponent.js
_processPendingState: function(props, context) { // props: nextProps
  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 = Object.assign({}, replace ? queue[0] : inst.state);
  for (var i = replace ? 1 : 0; i < queue.length; i++) {
    var partial = queue[i];
    Object.assign(
      nextState,
      typeof partial === 'function'
        ? partial.call(inst, nextState, props, context) // nextProps
        : partial,
    );
  }

  return nextState;
}

经过地点组件更新的流水生产线代码能够看到:

  • 在 updateComponent 中,在 component威尔ReceiveProps 之后才会盘算
    nextState,所以在 component威尔ReceiveProps 中 setState
    是足以在当次立异中生效的。
  • 在 _processPendingState 会对队列里的 state
    进行叠加,假若改动是函数格局,此处传入的state参数是 nextState,props
    是 nextProps。

更新: componentWillReceiveProps

  1. 在组件接收到新的 props 的时候调用
    ; 在伊始化渲染的时候,该方式不会调用
  2. 用此函数能够看成 react 在 prop 传入之后, render() 渲染从前更新
    state 
  3. 老的 props 能够经过 this.props 获取到
  4. 在该函数中调用 this.setState() 将不会挑起第二次渲染。
  5. 只顾:对于 state,没有相似的艺术,如若供给在 state
    改变的时候实施一些操作,请使用 componentWillUpdate4858美高梅,。
  6. 例子

    React.createClass({
      componentWillReceiveProps(nextProps) {
       this.setState({
      })
      }
    });
    

     

跻身一个路虎极光N界面时,Component的宣示周期函数差不多流程如下:

1.constructor构造函数,从上2个界面传过来的数额props在作为constructor的参数,在constructor中做一些起先化的操作,如props,state等起先化;函数原型:void
constructor(props)

2.component威尔Mount,第一回绘制组件(render)前触发该生命周期函数;函数原型:void
component威尔Mount()

3.render绘制组件到界面上;函数原型:void render()

4.componentDidMount,第一回挥之组件(render)后触发该生命周期函数,触发该函数表明奥迪Q7N组件绘制已经成功了,虚拟DOM已经创设实现;从那一个函数初始大家就足以和JS其余框架早先相互了,例如定时器,互联网请求等操作。函数原型:void
componentDidMount()

5.component威尔ReceiveProps,当组件收到新的属性时,触发该函数。函数原型:void
component威尔ReceiveProps( object nextProps )

6.shouldComponentUpdate,当组件属性(props)恐怕状态(state)发生变化时,都会触发该函数。函数原型:boolean
shouldComponentUpdate( object nextProps, object nextState );

若函数重回true,则继续触发componentWillUpdate,render,componentDidUpdate等措施;若函数重临false,则不做别的处理;

默许景况下,这些函数永远重临true用来保险数据变化的时候 UI
能够联手立异。在大型项目中,你可以协调重载那个函数,通过检查变化前后属性和情景,来支配
UI 是不是需求更新,能有效升高利用性能。

7.component威尔Update,即使组件状态恐怕性质改变,并且上边包车型地铁shouldComponentUpdate(object
nextProps, object nextState)再次回到为true,则触发该措施,函数原型:void
component威尔Update(object nextProps, object
nextState),函数中参数实际上与shouldComponentUpdate中的参数一样,是同1个数据源;

急需尤其注意的是,在那一个函数里面,你就不能动用this.setState来修改情形,不然会循环调用该函数导致堆栈溢出。那个函数调用之后,就会把nextProps和nextState分别设置到this.props和this.state中。紧接着这一个函数,就会调用render()来更新界面了。

8.componentDidUpdate,更新render结束后,则调用该方法,函数原型:void
componentDidUpdate(object prevProps, object
prevState);因为到那边曾经完毕了品质和状态的创新了,此函数的输入参数变成了prevProps和prevState。

9.component威尔Unmount,当组件要被从界面上移除的时候,就会调用component威尔Unmount(),函数原型:void
component威尔Unmount();在那个函数中,能够做一些组件相关的清理工作,例如裁撤计时器、网络请求等。

疑问:

 
在执行进度中,小编在页面销毁时,也会触发component威尔Update,render,componentDidUpdate,component威尔Unmount那样的3个流程,假诺有明白的人指望能够解答下~

Preact

主要代码:

Preact

紧要代码:

更新: shouldComponentUpdate

  1. 返回:boolean; 参数1:object nextProps ; 参数2:object nextState
  2. 在吸收到新的 props 或然 state,将要渲染在此之前调用 ;
    该措施在起初化渲染的时候不会调用
    ; 使用 forceUpdate 方法的时候也不会
  3. 如若分明新的 props 和 state
    不会造成组件更新,则此处应该 返回 false。默许情状下,shouldComponentUpdate 总会回来
    true
  4. 一旦 shouldComponentUpdate重返false,则 render()
    将不会实施,直到下3遍 state 改变。此外,component威尔Update 和
    componentDidUpdate 也不会被调用
  5. 例子

    React.createClass({
      shouldComponentUpdate(nextProps, nextState) {
      return false
      }
    });
    

     

setState 阶段:

// component.js
setState(state, callback) {
  let s = this.state;
  if (!this.prevState) this.prevState = extend({}, s);
  extend(s, typeof state==='function' ? state(s, this.props) : state);
  if (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);
  enqueueRender(this);
}

落到实处的简易冷酷,在 setState 的时候就开始展览了统一,会即时改写
this.state,在第②遍 setState 时会保留 state 状态到
prevState。由于是随即联合state,假若入参state是函数,props 将只是最近this.props。

setState 阶段:

// component.js
setState(state, callback) {
  let s = this.state;
  if (!this.prevState) this.prevState = extend({}, s);
  extend(s, typeof state==='function' ? state(s, this.props) : state);
  if (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);
  enqueueRender(this);
}

兑现的简约阴毒,在 setState 的时候就开展了合并,会马上改写
this.state,在率先次 setState 时会保留 state 状态到
prevState。由于是随即联合state,假如入参state是函数,props 将只是目前this.props。

更新: componentWillUpdate

  1. 参数1:object nextProps  参数2:object nextState
  2. 在接收到新的 props 也许 state
    此前及时调用。在发轫化渲染的时候该措施不会被调用。
  3. 瞩目:你不能在刚方法中动用 this.setState()。假若要求更新 state
    来响应有些 prop 的更改,请使用 componentWillReceiveProps
  4. 例子

    React.createClass({
      componentWillUpdate(nextProps, nextState) {
      ...
      }
    });
    

     

更新阶段:

export function renderComponent(component, opts, mountAll, isChild) {
  ...
  previousProps = component.prevProps || props,
  previousState = component.prevState || state,
  previousContext = component.prevContext || context,
  ...

  // if updating
  if (isUpdate) {
    component.props = previousProps;
    component.state = previousState;
    component.context = previousContext;
    if (opts!==FORCE_RENDER
      && component.shouldComponentUpdate
      && component.shouldComponentUpdate(props, state, context) === false) {
      skip = true;
    }
    else if (component.componentWillUpdate) {
      component.componentWillUpdate(props, state, context);
    }
    component.props = props;
    component.state = state;
    component.context = context;
  }
  ...
}

在革新流程前领到了旧 state,shouldComponentUpdate、component威尔Update
之后苏醒回新值,所以在 shouldComponentUpdate 生命周期中,this.props
将赢得的是 prevProps,这里与 React 的逻辑并差异。

更新阶段:

export function renderComponent(component, opts, mountAll, isChild) {
  ...
  previousProps = component.prevProps || props,
  previousState = component.prevState || state,
  previousContext = component.prevContext || context,
  ...

  // if updating
  if (isUpdate) {
    component.props = previousProps;
    component.state = previousState;
    component.context = previousContext;
    if (opts!==FORCE_RENDER
      && component.shouldComponentUpdate
      && component.shouldComponentUpdate(props, state, context) === false) {
      skip = true;
    }
    else if (component.componentWillUpdate) {
      component.componentWillUpdate(props, state, context);
    }
    component.props = props;
    component.state = state;
    component.context = context;
  }
  ...
}

在更新流程前领取了旧 state,shouldComponentUpdate、component威尔Update
之后苏醒回新值,所以在 shouldComponentUpdate 生命周期中,this.props
将取得的是 prevProps,那里与 React 的逻辑并不雷同。

更新: componentDidUpdate

  1. 参数1:object prevProps  ; 参数2:object prevState
  2. 在组件的翻新已经联合署名到 DOM
    中之后登时被调用。该措施不会在初步化渲染的时候调用
  3. 使用该办法能够在组件更新之后操作 DOM 成分。
  4. 留神:为了协作 v0.9,DOM
    节点会作为最终一个参数字传送入。假诺利用那么些艺术,你依旧能够选用 this.getDOMNode()来访问
    DOM 节点
  5. 例子

    React.createClass({
      componentDidUpdate(nextProps, nextState) {
      ...
      }
    });
    

     

 

 

划重点

相同点:

  • 在 component威尔ReceiveProps 中 setState 都会选用到 nextState。
  • 在 shouldComponentUpdate 中 setState 都会接纳到
    nextState,不过能够直接操作传入的 nextState。

不同点:

  • React下 setState 的值不会马上生效,会一直积累到
    component威尔ReceiveProps,在此之后会进展统一,并提要求后续生命周期。而Preact下
    setState 会立时反映到 this.state,但是,在更新组件的生命周期到
    render 前(eg: shouldComponentUpdate), this.state 将会是 prevState。
  • shouldComponentUpdate 阶段 setState 纵然不会潜移默化到终极 state
    的值,然则Preact下会影响 this.state 的值,比如之后
    component威尔Update 中的 this.state, 由此可见此阶段不要 setState
    反正也没用。
  • setState 借使选拔函数修改,Preact下传入的 props 将会是
    prevProps,而React中是 nextProps,在 component威尔ReceiveProps 中
    setState 时要注意。

划重点

相同点:

  • 在 component威尔ReceiveProps 中 setState 都会动用到 nextState。
  • 在 shouldComponentUpdate 中 setState 都会利用到
    nextState,可是足以一直操作传入的 nextState。

不同点:

  • React下 setState 的值不会及时生效,会直接积累到
    component威尔ReceiveProps,在此之后会开始展览合并,并提需求后续生命周期。而Preact下
    setState 会马上反映到 this.state,但是,在更新组件的生命周期到
    render 前(eg: shouldComponentUpdate), this.state 将会是 prevState。
  • shouldComponentUpdate 阶段 setState 就算不会影响到结尾 state
    的值,不过Preact下会潜移默化 this.state 的值,比如之后
    component威尔Update 中的 this.state, 同理可得此阶段不要 setState
    反正也没用。
  • setState 假使运用函数修改,Preact下传入的 props 将会是
    prevProps,而React中是 nextProps,在 component威尔ReceiveProps 中
    setState 时要专注。

事例: 路由切换时,组件生命周期的更动情形


总结

假设你写的工程供给同时兼容React及Preact的话:

  • 不要动用React下 setState 在平等次组件更新实施前 state
    不比时更新的特征,注意五个 setState
    之间是不是影响,供给时手动保存旧值。
  • 在组件更新生命周期内,除 component威尔ReceiveProps 之外不要选择setState,提供了 nextState 的生命周期,能够一贯修改 nextState。
  • 尽量防止使用 setState 函数修章,在 component威尔ReceiveProps
    中央银行使时,使用生命周期中的 prevProps(this.props) 和 nextProps。

p.s: antd-mobile
2.0正规版已揭橥,同时包容react、preact,轻量、火速、易用的运动端组件库,等您来用~
【传送门】

总结

假定您写的工程要求同时包容React及Preact的话:

  • 不要运用React下 setState 在平等次组件更新实施前 state
    不比时更新的特色,注意三个 setState
    之间是不是影响,须要时手动保存旧值。
  • 在组件更新生命周期内,除 componentWillReceiveProps 之外不要选拔setState,提供了 nextState 的生命周期,能够平素修改 nextState。
  • 尽量防止使用 setState 函数修章,在 component威尔ReceiveProps
    中行使时,使用生命周期中的 prevProps(this.props) 和 nextProps。

p.s: antd-mobile
2.0规范版已发表,同时包容react、preact,轻量、快捷、易用的移动端组件库,等您来用~
【传送门】

 

路由配置如下:

<Route path="/" component={App}>
  <IndexRoute component={Home}/>
  <Route path="invoices/:invoiceId" component={Invoice}/>
  <Route path="accounts/:accountId" component={Account}/>
</Route>

1. 当用户打开应用的 ‘/’ 页面

4858美高梅 2

 

2. 当用户从 ‘/’ 跳转到 ‘/invoice/123’

  • App 从 router 中吸收接纳到新的
    props(例如 childrenparamslocation 等数据),
    所以 App 触发了 componentWillReceiveProps 和 componentDidUpdate 三个生命周期方法

  • Home 不再被渲染,所以它将被移除,触发 componentWillUnmount

  • Invoice 第壹回被挂载 触发 componentWillMount 和 componentDidMount

4858美高梅 3

 

3. 当用户从 /invoice/123 跳转到 /invoice/789

  • 具备的零部件从前都早就被挂载, 所以只是从 router 更新了 props. 

4858美高梅 4

 

4. 当从 /invoice/789 跳转到 /accounts/123

 4858美高梅 5

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有