vue生命周期和react生命周期总结对比

vue框架和react框架虽然都是虚拟dom,组件化开发,其中的不同点还是蛮多的。首先vue的双向绑定而react则是单项数据流。react使用了jsx语法,让编程更组件话。除了这些他们的生命周期还是不一样的

总归他们都经历了 初始化阶段,运行阶段,销毁阶段。其中运行阶段又分渲染和数据更新两部分

先说下vue的生命周期相对比较简单:

初始化阶段:

1:new Vue(...) : 实例化、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作

2:beforeCreate,created :挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

运行阶段:

1:beforemounted:接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取

2:render ,mounted,beforeupdate,update : 接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom。

到这里还不算结束,如果在程序运行中,没有更新数据则无视,一旦有数据更新了,就会走以下两个钩子:beforeupdate,update

当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom

销毁阶段:

1:beforeDestroy:当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

2:destroyed:组件的数据绑定、监听...去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

总结起来无外乎就七个当然真实的流程要更细致复杂,有兴趣的可以自己研究源码,实际项目中用到这些完全够了:

newVue()实例化 => beforeCreate,created =>beforemounted,mounted =>(if data change){ beforeupdate,update } => beforedestroyed,destroyed

这里有几点要注意:

1:Vue的编译实际上是指Vue把模板编译成 render 函数的过程

2:render选项参数比template更接近Vue解析器!所以综合排列如下:

  render函数选项  > template参数  > 外部HTML
3:通过Vue.compile这个实时编译模板的函数来看一看:
用官方文档的例子
<div>
  <header>
    <h1>I'm a template!</h1>
  </header>
  <p v-if="message">
    {{ message }}
  </p>
  <p v-else>
    No message.
  </p>
</div>
会被渲染成:
function anonymous() {
  with(this){return _c('div',[_m(0),(message)?_c('p',[_v(_s(message))]):_c('p',[_v("No message.")])])}
}

4:在Vue中,数据更改会导致虚拟 DOM 重新渲染,并先后调用beforeUpdate钩子函数和updated钩子函数

重渲染(调用这两个钩子函数)的前提是被更改的数据已经被写入模板中!!(这点很重要)

var vm = new Vue({
  el: '#app',
  data: {
    number: 1
  },
  template: '<div id="app"><p></p></div>',
  beforeUpdate: function () {
    console.log('调用了beforeUpdate钩子函数')//控制台没有打印
  },
  updated: function () {
    console.log('调用了updated钩子函数')//控制台没有打印
  }
})
 
vm.number = 2
// 在模板中使用number这个数据
  template: '<div id="app"><p>  {{ number }} </p></div>',//添加{{number}}

beforeUpdate: function () {
    console.log('调用了beforeUpdate钩子函数')//此时被打印出来了
  },
  updated: function () {
    console.log('调用了updated钩子函数')//此时被打印出来了
  }

也就是说:只有Vue实例中的数据被“写入”到我们的模板中,它的改变才可以被Vue追踪,重渲染从而调用 beforeUpdate钩子函数和updated钩子函数

5:

beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
 
destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
 
就如同调用在Vue实例上调用$mounted会使暂停的生命周期继续一样,调用$destroy()会直接销毁实例
 
接下来看react生命周期,它相对于vue生命周期流程差不多但相对复杂点:
 初始化阶段:
1:首先是创建构造函数constructor 类似vue实例化new vue()
执行时间:组件被加载前最先调用,并且仅调用一次。作用:定义状态机变量 
constructor(props) {
    super(props);//如果有父元素继承父元素的props
    this.state = {
      content:null,
    }
}

执行阶段:

1:componentWillMount():这个函数是在render前执行一次,如果在这个函数中调用setState改变某些状态机,react会等待setState完成后再渲染组件

需要注意的是:如果有子组件,子组件也有此钩子函数,并且会等待父级的函数调用完成后才会调用子组件的componentWillMount

 2:render():主要用来渲染挂载组件。也是组件的最核心函数,和其它钩子函数不一样(上一个钩子只执行一次)render函数是比较频繁被调用的:(1)初始化加载页面(2)状态机改变setState ( 3 ) 接收到新的props(父组件更新)

需要注意的是render钩子内不要改变状态机state

3:componentDidMount():render之后就会调用,它也和componentWillMount一样只调用一次。它的主要作用就是渲染挂组件可以使用refs了。(如果需要操作dom时)

需要注意的是子组件也有componentDidMount,不过和willMount不同的是子组件会在父组件调用前调用didMount

如果在该函数内修改state,render就会被再次调用。

如果不想多次渲染render,可以选择将setState放在willMount内。

它比较适合数据初始化后,再异步的请求后端接口或其它数据需要再次更新页面响应式的时候,请求的接口可以直接放在这里

数据更新监测阶段:(如果有数据改变的话):

1:componetWillReceiveProps():上面的是第一遍流程,当后期有新的props传入,react会调用willReceiveProps钩子,换句话说,父组件内state值改变了,就会重新渲染render,父组件一render,子组件的props就更新了,也就调用了此钩子

它的作用和didMount相似,也可以渲染挂在组件使用refs

需要注意的是:react初次渲染时,该函数并不会被触发,因此有时该函数需要和componentWillMount或componentDidMount组合使用;

使用该函数一定要加nextProps参数:componentWillReceiveProps(nextProps),首次使用了解的可以先打印结果(console.log(nextProps))

2:shouldComponentUpdate() : 每次执行setstate都会执行该函数,也就是说只要一改变状态,接收到新的state或props 就会调用此更新机制:它有默认的返回值 true,有两个参数:新的props,新的state:sholdComponentUpdate(nextprops,nextstate)

它的作用是:如果有些变化不需要重新render组件,可以在该函数中阻拦。

注意:该方法在初始化渲染的时候不会调用,在使用 forceUpdate 方法的时候也不会

3:componentWillUpdate():每次执行setstate后,如果setState跟新改变了props,state也就是说通过setstate改变为新的prop,state值,它就会被调用,注意是在重新render前,所以它作用也是在获取新的prop,state后,为下次render做准备工作

注意:不能再该函数中通过this.setstate再次改变状态机,如果需要,则在componentWillReceiveProps函数中改变

4:componentDidUpdate():重新渲染后调用,在初始化渲染的时候该方法不会被调用

作用:使用该方法可以在组件更新之后如果还想操作DOM 元素的话可以在此写入操作

最后是销毁阶段,这里只有一个componentWillUnmount()

 在该方法中执行任何必要的清理,比如无效的定时器,或者清除在 componentDidMount 中创建的 DOM 元素。

 需要注意的是:

1:当一个页面中存在子父组件时,要注意componentWillMount和componentDidMount的使用,如果需要先加载父组件(获取网路数据),父组件传值给子组件,再加载子组件(获取网路数据),那么不能同时在子父组件中使用componentDidMount获取网路数据,因为会先执行子组件的componentDidMount,会由于未得到父组件的传值而报错;解决方案:(1)父组件:componentWillMount,子组件:componentDidMount;(2)父组件:componentDidMount,子组件:componentWillMount;
他们的真确顺序应该是:父componentWillMount => 子componentDidMount=>父componentDidMount=>子componentWillMount

2:当一个页面中如要实现两个组件的联动效果,(比如:页面中包含componentA和componentB,单击componentA,componentB内容对应变化,componentA向componentB通过redux传参,那么componentB首次会通过componentDidMount接收,然后再通过componentWillReceiveProps接收)

需要额外注意的是:react17版本以后:有些生命周期基本弃用了(过时):不建议使用因为强制使用它们还是会有效

1:componentWillMount():建议在constructor()内初始化state,如果是订阅类建议在componentDidMount()内进行

2:componentWillReceiveProps():如果执行数据提取以响应props的更改,请改为componentDidupdate()生命周期,如果是为了在props更改后重置某些state,请考虑组件完全受控或使用key使组件不受控来代替

3:componentWillUpdate():不能在此调用setState(),通常情况下此方法替换成componentDidupdate()。如果想要读取dom信息(如保存滚动位置)可将逻辑移至getSnapshotBeforeUpdate()中

另外还有个生命周期是不常用的:shouldcomponentUpdate:只作为性能优化的方式存在,不要在这里做阻止渲染等操作会出现bug

注意,你不能此方法中调用 this.setState();在 UNSAFE_componentWillUpdate() 返回之前,你也不应该执行任何其他操作(例如,dispatch Redux 的 action)触发对 React 组件的更新 

通常,此方法可以替换为 componentDidUpdate()。如果你在此方法中读取 DOM 信息(例如,为了保存滚动位置),则可以将此逻辑移至 getSnapshotBeforeUpdate() 中。

posted @ 2020-06-12 10:22  少哨兵  阅读(1188)  评论(0编辑  收藏  举报