【框架对比】React和Vue的生命周期

3,421 阅读3分钟

一、react

react生命周期

包括:数据初始化、创建、挂载、更新、销毁

react生命周期在项目中的执行顺序

constructor() => componentWillMount() => render() => componentDidMount()

当更新执行直接执行以下:

componentWillReceiveProps (nextProps) => shouldComponentUpdate(nextProps,nextState) => componentWillUpdate (nextProps,nextState) => render() => componentDidUpdate(prevProps,prevState)

关闭页面组件最终都会销毁: componentWillUnmount ()

react新增的生命周期:

  1. getDerivedStateFromProps(nextProps, prevState)

  2. getSnapshotBeforeUpdate(prevProps, prevState)

强调几点:

  1. constructor()中完成了React数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。注:只要使用了constructor()就必须写super(),否则会导致this指向错误

  2. render()中会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

getDerivedStateFromProps()代替componentWillReceiveProps()

在 componentWillReceiveProps 中,一般会做以下两件事:

  1. 根据 props 来更新 state
  2. 触发一些回调,如动画或页面跳转等。

componentWillReceiveProps缺点:

  1. 会破坏 state 数据的单一数据源,导致组件状态变得不可预测
  2. 也会增加组件的重绘次数
  3. 更新state和触发回调都在componentWillReceiveProps中执行

getDerivedStateFromProps优点:

  1. getDerivedStateFromProps 中禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。

  2. 更新 state在getDerivedStateFromProps中,触发回调在componentDidUpdate中,使得组件整体的更新逻辑更为清晰

// before
componentWillReceiveProps(nextProps) {
  if (nextProps.isSuccess !== this.props.isSuccess) {
    this.setState({ 
      isLogin: nextProps.isSuccess,   
    });
  }
  if (nextProps.isSuccess) {
    this.close();
  }
}

// after
static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.isSuccess !== prevState.isSuccess) {
    return {
      isLogin: nextProps.isSuccess,
    };
  }
  return null;
}

componentDidUpdate(prevProps, prevState) {
  if (!prevState.isSuccess && this.props.isSuccess) {
    this.close();
  }
}

getSnapshotBeforeUpdate()代替componentWillUpdate()

componentWillUpdate的常见用例:读取当前某个 DOM 元素的状态,并在 componentDidUpdate 中进行相应的处理

componentWillUpdate的缺点:

  1. 在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了

getSnapshotBeforeUpdate的优点:

  1. getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。
  2. 此生命周期返回的任何值都将作为参数传递给componentDidUpdate()

二、vue

vue生命周期

vue每个组件都是独立的,每个组件都有一个属于它的生命周期。

包括:数据初始化、创建、挂载、更新、销毁

vue生命周期在项目中的执行顺序

beforeCeate() => data() => created() => beforeMount() => mounted()

当更新会再created之后插入: beforeUpdate => updated

关闭页面组件最终都会销毁: beforeDestroy() => destroyed()

强调几点:

  1. beforeCeate在事件和生命周期钩子初始化前调用
  2. data的初始化是在created前完成数据观测(data observer)
https://github.com/vuejs/vue/blob/dev/src/core/instance/init.js

initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')

vue中内置方法属性的运行顺序(methods、computed、data、watch、props)

从源码可以知道: props => methods =>data => computed => watch

https://github.com/vuejs/vue/blob/dev/src/core/instance/state.js

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

几点注意

  1. 异步请求最好在mounted中执行
  2. $refs获取dom元素,在$nextTick中执行
  3. $refs直接访问子组件的方法,可能有数据的延迟滞后的bug,可以采用异步回调的方式解决
handleAsync () {
   return new Promise(resolve=>{
       resolve(res)
   })
}
async handleShow() {
    await this.handleAsync().then(res=>{
    	this.$refs.child.fun(res);
    })
}

比较

相同点:

  1. react和vue异步请求都最好在挂载函数(componentDidMount和mounted)中执行
  2. 生命周期都包含:初始化、创建、挂载、销毁、更新
  3. 都是通过refs获取dom元素
  4. 都需要进行卸载和数据的销毁:setTimeout、setInterval、removeEventListener等

不同点:

  1. 更新过程挂载阶段生命周期不一样,react用新函数componentDidUpdate,vue还是用mounted
  2. 写法大不一样

www.jianshu.com/p/b331d0e4b…