angular1与react生命周期对比

本文对比了React与Angular1的生命周期,详细介绍了React的挂载、更新与卸载阶段,以及Angular1从1.5版本后改进的生命周期钩子。通过对两种框架生命周期的解析,帮助读者更好地理解组件的状态管理。

能否理解一个组件的生命周期是非常重要的,甚至可以说是最重要的内容,他是一切进阶的基石,下面我们就从angular1的生命周期开始吧。

angular1生命周期

angular1的生命周期在1.5之前是很晦涩的,controller、compile、preLink、postLink,compile的return函数。从字面上让人完全摸不着头脑,到了1.5增加了angular.component,这一问题有了很大改观,生命周期全部放到controller(controller不再作为一个生命周期钩子存在),controller就是一个class,实例函数$onInit、$onPostLink和$onDestroy组成了新的生命周期钩子,从字面上也容易理解了很多。$onInit代表编译前,在这里你可以对$scope做属性变更,和逻辑定义;$onPostLink代表编译后,这个时候子指令已完成了编译,你可以在这里获取到任意子指令实例并调用其方法;$onDestroy在当前scope被销毁时调用,在这里你需要对dom做销毁,以及可能的全局变量做清空。很简单就是组件编译前、组件编译后和组件销毁时。那么我们再看看react的生命周期钩子。

react生命周期

react的生命周期分为三大阶段,

  • 插入dom(mount)
  • 重新render(update)
  • 销毁dom(unmount)

在定义class(组件)的时候其实就是在定义一个状态机,定义了各种状态的响应,这里包括这三大阶段的钩子以及事件响应,等待触发条件的满足。

1 插入dom(mount)

先来说下第一阶段,首次render触发时会执行以下钩子函数,

  • getDefaultProps
    getDefaultProps: function(){
      return { /* 默认属性 */};
    }复制代码
  • getInitialState

    getInitialState: function(){
      return { /* 初始状态 */};
    }复制代码

    这两个函数不难理解,目的是使代码结构更清晰,不需要在constructor里做过多的打底处理。

  • componentWillMount
    这个方法在出现class XX extends React.Component之后其实就可以用constructor来代替了。对于angular1.5这和$onInit也是类似的,同样也可以用constructor代替。

  • render
    这个函数其实和angular指令中的template属性(值对应一个函数)很相似,但是借助jsx,render比template属性强大实在太多,angular所提供的template不够灵活,在template函数中无法拿到$scope,自然我们就选择例如ngIf这样的属性指令来做模版输出控制,该指令会在当前指令作用域下再创建一个子作用域,这使得我们在获取子组件的实例的时候会比较麻烦,ngRepeatngSwitch都是这样,angular1的初衷是不希望我们自己做字符串拼接,的确就算我们能拿到$scope,字符串拼接也实在不够优雅。
    所以render函数直白点完成了两件事情:

    • 执行jsx表达式,生成最终插入dom容器节点的真实dom(这里不考虑虚拟dom的问题)
    • 借助react提供的synthetic event system完成事件监听绑定

    所有叶子组件的jsx模版都是由基础原生html标签、属性以及react所提供的代理属性组成的,因此如果你写如下一段模版代码:

    render(){
      return (
          <div num=1 changehandler={this.changeHandler.bind(this)}/>
      )
    }复制代码

    numchangehandler属性会直接被忽略,如果你想在原生标签上使用自定义属性,请在属性前面添加data-

  • componentDidMount

    componentDidMount和angular中的link或postLink很相似,但是它更让人放心,因为angular中如果你想在link中获取带有ngIf或ngRepeat的dom是获取不到的(因为会再transclude一次并等待下次脏数据校验才会插入dom,有兴趣的同学可以移步重复transcludengIf脏数据校验),因此在这里你可以放心的访问dom。

    小结:上述方法除了render,只会伴随第一次render执行一次。

2 重新render

当组件props和state(通过setState)发生变更时,会触发re-render操作。因此这里我们把state和props变化分开来说。

在angular1中其实并没有多次触发的钩子,像前面说到的controller、compile等也都只执行一次,其实react的重新渲染在angular类似$watch,一般我们在$watch来实现dom的变更,这种命令式的修改dom当然是不推荐的,react采用了一种更彻底的方式,给人的感受就像又走了一遍第一次渲染一样,而你可以这样理解,相对于第一次,它可能仅仅变更了个别state或props,通过虚拟dom和diff算法,react帮助你高效的将变更应用于虚拟dom上最终re-render出新的dom树。

2.1 state变更

状态变更会触发以下几个钩子

  • shoudComponentUpdate
      shouldComponentUpdate: function(nextProps, nextState){
          return true
      }复制代码
    该函数给用户一个机会使得其可以控制是否需要进行重新渲染,angular1并没有提供终止指令编译的钩子函数,这是react的高级特性了,主要针对性能优化,自己没有用过就不误导大家了。
  • componentWillUpdate

      componentWillUpdate: function(nextProps, nextState){
      // 为re-render做准备
      }复制代码

    为啥需要这个钩子呢,因为只有shouldComponentUpdate返回true才能确定一定会重新渲染,那么在这里我们可以对界面的提示UI做变更,比如之前为了获取state或props会因为异步请求出现loading,那么这个时候就可以隐藏loading。记住这里不能有任何会再次触发组件重新渲染的逻辑。

  • componentDidUpdate

    componentDidUpdate: function(prevProps, prevState){
      // 可以访问渲染完成的dom
    }复制代码

    这个没啥可说的,和componentDidMount是一样的。

2.2 props变更

componentWillReceiveProps: function(nextProps) {
  this.setState({
    // new state
  });
}复制代码

不像state需要调用setState才会触发re-render,由父组件导致的任何属性变更都会触发re-render,不需要调用额外的方法。其实props变更所经历的生命周期钩子和state几乎一样,唯一不同是在shouldComponentUpdate之前增加了componentWillReceiveProps,用意也十分明显,我们可以在componentWillReceiveProps中通过setState对state做修改,比如组件内部的state是根据某个或多个props计算得出的,这样我们在调用setState时候也不会造成额外的re-render被触发,深入理解react

3 销毁dom(unmount)
当我们改变UI布局或者使用接口删除组件树上某个组件时就会触发组件的componentWillUnmount方法,在这里你可以取消事件监听或定时器,以及其他会造成全局引用的变量。

class App extend Component {
    componentWillUnmount(){
        // unregister event or clear timer
    }
}
render(<App />, document.getElementById('root')

function ummount(){
    React.unmountComponentAtNode(document.getElementById('root'));
}复制代码

4 结束
这篇其实和angular1的对比不是太多,但其实大概的生命周期和angular1还是大同小异,特别是re-render这块更有条理也更有性能优势。react与angular1的对比先暂告一段落,后面将开始redux的学习,同时会对官方的demo做详细讲解。

文中如有错误请大家及时纠正,谢谢。

转载于:https://juejin.im/post/59048e54ac502e0063e3de69

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值