Vue2.x生命周期中的钩子函数的一些注意事项

1,270 阅读7分钟

关关难过, 关关过 :)

1.beforeCreat

beforeCreate在实例初始化之后、数据观测(data observer)和事件配置之前被调用。在 beforeCreate 钩子函数中,Vue 实例已经完成了数据观测的设置,但尚未初始化,也没有 DOM 相关操作,因此在这个钩子函数中还不能访问数据或组件模板,也不能操作 DOM 元素。

数据观测(data observation)指的是 Vue 响应式系统对组件数据的监测,当组件数据发生变化时,Vue 会自动触发视图更新。这是 Vue 实现响应式的核心机制。

通常在 beforeCreate 中可以做一些初始化的工作,例如初始化数据、获取远程数据、设置事件监听器等,但需要注意的是,在 beforeCreate 中对数据进行的修改是不会触发视图更新的,因为此时 Vue 实例还未初始化完成。

如果在beforeCreate阶段中获取的数据需要在Vue实例的生命周期中使用,需要在数据返回后手动调用this.$forceUpdate()来触发Vue实例的重新渲染。

注意
beforeCreate 钩子函数中对实例的数据进行修改是无效的,因为实例的数据和方法尚未初始化。在这个钩子函数中有this对象, 这个this并不能访问data和props。你可以通过函数的参数来访问到这些数据,但在这个时候组件实例还没有完成数据的响应式化, 也就是说, 此时仅能读取它们的值,而不能修改

beforeCreate() {
    console.log(this.$options.data()) // 访问 data
    console.log(this.$options.propsData) // 访问 props 
}

2.created

created钩子函数是Vue实例创建完成后执行的第一个函数。在这个钩子函数中,Vue实例已经完成了数据的观测,可以访问到实例中的data数据以及props属性。此时模板已经编译成了虚拟DOM,但是还没有被渲染成真实的DOM。

created钩子函数中,我们可以进行一些实例的初始化操作,例如发送异步请求获取数据、调用methods中的方法等。在这个阶段,我们可以访问到dataprops中的数据,并可以对它们进行修改,但是不能保证这些修改能够立即更新到视图中,因为此时模板还没有被渲染成真实的DOM。

需要注意的是,created钩子函数执行完毕后,才会进入到模板的编译和挂载阶段,因此,在created钩子函数中进行的异步操作,不会阻塞模板的编译和挂载。如果需要在模板被渲染之后执行一些操作,可以使用mounted钩子函数。

3.beforeMount

beforeMount 钩子函数是 Vue 生命周期中的一个阶段,在模板编译完成并准备渲染到页面上之前调用。在这个阶段,Vue 实例已经完成了数据的观测和与数据的绑定,但还没有开始创建真正的 DOM 节点。

beforeMount 钩子函数中,可以访问到 Vue 实例的所有属性和方法。 但要注意,如果需要修改数据,应该在 beforeMount 钩子函数之前进行,因为此时 Vue 实例的数据已经与 DOM 节点绑定,如果在beforeMount 中修改数据,实际上是在生成 VNode 的过程中修改了组件实例的数据,此时这些数据还没有被同步到真实的 DOM 节点上。可能会导致视图与数据不同步。

4.mounted

mounted 钩子是在组件挂载到DOM上后调用的钩子函数,可以理解为组件生命周期的最后一个阶段。该钩子函数一般用于获取DOM节点、初始化第三方库、发送异步请求等等操作。

具体来说,在 mounted 钩子执行期间,组件实例已经被编译成真实的DOM,并且该DOM节点已经被添加到页面上,所以在这个钩子中可以访问this.$el,即当前组件的根节点标签,并可以进行一些需要访问DOM节点的操作,例如使用jQuery或原生DOM API等。

在执行 mounted 钩子期间,Vue会将组件的DOM节点和组件实例关联起来,形成一个双向绑定关系,从而实现数据的自动响应式更新。

需要注意的是,如果在 mounted 钩子中进行的操作需要在组件销毁时进行清理,那么必须在 beforeDestroy 钩子中进行相应的清理工作,例如定时器、绑定的事件监听器等,如果没有进行清理操作,在组件销毁后,相关的数据和事件监听器就会一直存在于内存中,导致内存泄漏问题,影响应用的性能和稳定性。

因此,在编写 Vue 组件时,需要注意这个问题,及时清理组件中创建的数据和事件监听器,避免内存泄漏。

5.beforeUpdate

在数据更新时,在 updated 钩子函数之前被调用。它可以用来检测数据的变化、执行一些特定的操作以及阻止不必要的重渲染。 在 beforeUpdate 钩子函数中,可以访问到组件实例的 this 对象以及更新前的数据和状态。通过对比更新前后的数据和状态,可以判断是否需要进行重渲染,并作出相应的处理。

beforeUpdate 钩子中直接修改数据是不会导致死循环的,不管新旧值是否相同,只要数据被修改,Vue 会进入下一次的渲染周期。

这个钩子是在组件更新之前被调用,此时组件的 DOM 尚未更新,Vue 会对新旧虚拟 DOM 树进行比对,以确定需要对哪些节点进行更新。如果在 beforeUpdate 钩子中修改了组件的数据,那么这些数据会在下一次更新时生效,从而触发新的 beforeUpdate 钩子调用。因此,在 beforeUpdate 中修改数据通常没有意义,因为这些修改不会立即生效,也可能导致一些意料之外的行为。

同时在这个钩子函数中,也可以使用 watch 来监听数据的变化,并在变化时执行相应的操作。例如,可以监听组件中的某个数据对象,并在其变化时执行一些特定的操作。

注意
beforeUpdate 钩子函数中,还不能访问到更新后的 DOM 节点,因为此时更新过程还没有完成,新的节点还没有渲染出来。如果需要在 DOM 更新完成后进行一些操作,可以在 updated 钩子函数中执行。

6.updated

这个钩子函数常常用于执行一些需要在组件更新后进行的操作,比如 DOM 操作或者与服务器的交互。下面从源码角度来详细解释 updated 钩子的实现过程:

  1. Vue.js 会在更新前执行 beforeUpdate 钩子函数,该函数在组件的数据更新之前被调用。 beforeUpdate 函数会将当前的渲染 watcher 添加到观察者列表中,以便在更新后能够被执行。
  2. Vue.js 然后会调用 updateComponent 函数,该函数会重新渲染组件,并更新组件的 VNode 树。
  3. 在组件的 VNode 树更新完成后,Vue.js 会执行 updated 钩子函数。在执行 updated 钩子函数之前,Vue.js 会先执行 activated 钩子函数(如果组件是被 keep-alive 缓存的话)。
  4. updated 钩子函数会接收两个参数:prevVNode 和 prevData,分别表示组件更新前的 VNode 和数据。通过这些参数,可以在 updated 钩子函数中比较组件更新前后的状态,从而执行一些需要在组件更新后进行的操作,比如 DOM 操作或者与服务器的交互。
  5. 最后,Vue.js 会从观察者列表中移除渲染 watcher,从而结束更新过程。

总的来说,updated 钩子函数是在组件的 VNode 树更新后被调用的,它允许开发者在组件更新后执行一些操作。Vue.js 的实现过程中,updated 钩子函数的执行是在 beforeUpdate 钩子函数、updateComponent 函数和 activated 钩子函数之后,通过移除渲染 watcher 来结束更新过程的。

注意
不要在这个钩子函数里做任何改变组件状态的操作,会无限循环导致堆栈溢出.

7.beforeDestory

beforeDestroy 生命周期钩子函数会在一个组件实例被销毁之前被调用。具体来说,它会在组件实例从 DOM 树中被移除之前被调用。

beforeDestroy 钩子函数中,Vue.js 会执行以下操作:

  1. 调用 vm.$off() 方法来移除组件实例上的所有事件监听器。这个方法会将组件实例上的所有事件监听器从事件总线中移除,以防止它们在组件实例被销毁后继续存在,从而导致内存泄漏。
  2. 调用 vm.$destroy() 方法来递归销毁组件实例上的所有子组件。这个方法会先递归销毁所有子组件上的子组件,然后再依次调用子组件实例的 beforeDestroydestroyed 钩子函数,完成子组件的销毁工作。
  3. 最后,调用 vm._isBeingDestroyed = true 将组件实例标记为正在被销毁的状态,然后触发组件实例的 beforeDestroy 钩子函数,执行用户定义的销毁逻辑。

由于 beforeDestroy 钩子函数是在组件实例销毁之前被调用的,因此它可以用于执行一些与销毁相关的清理工作,例如取消异步任务、释放资源等。同时,它也可以用于在组件实例销毁之前执行一些操作,例如提交最后一次数据到服务器等。

8.destoryed

destroyed 钩子函数是在组件实例被销毁之后执行的,它可以用于执行一些与销毁无关的操作,例如记录日志、清除定时器等。在这个钩子函数中,组件实例已经被销毁,可以在 destroyed 钩子中访问 datamethods,因为这些属性是在组件实例化时创建的,并且在组件销毁时仍然存在。但是它的状态和属性不会改变,因此这里做的任何操作都应该是与销毁无关的。

总的来说,beforeDestroy 钩子函数和 destroyed 钩子函数的主要区别在于执行时机和作用范围。beforeDestroy 钩子函数用于执行与销毁相关的操作,而 destroyed 钩子函数用于执行与销毁无关的操作。在实际开发中,应该根据具体的需求选择合适的钩子函数来完成相应的操作。

注意
如果有操作需要在卸载组件时进行,请使用beforeDestroy

补充:

  1. vue中生命周期的钩子里的操作会被vue移入微任务队列执行, 所以在这些钩子函数内进行的异步操作, 不能立刻体现出来。举个例子:
//this.name = 'aaaa'
created() {
  new Promise((resolve) => {
    resolve('111')
  }).then(r => {
    this.name = r
  })
},
mounted() {
  console.log(this.name) //'aaaa'
},

所有的异步操作会进入下一个微任务队列, 所以在这个例子中想要访问this.name改变后的结果,需要使用nextTick

mounted() {
  console.log(this.name) //'aaaa'
  this.$nextTick(() => {
    console.log(this.name)// '111'
  })
},
  1. 当组件已经渲染,而且mounted钩子中有setTimeout函数,在wait之前组件被销毁,这个setTimeout依然会执行。因为生命周期钩子被调用,组件卸载并不会中断其中函数的执行。