跳到主要内容

Vue3 的生命周期

Vue2 的生命周期​

Nonuz6.png

Vue3 的变更​

Vue3 进行了以下变更

  • beforeCreate -> setup()
  • created -> setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

几个需要注意的点

  • 在 Vue3.x 中,为了兼容 Vue2.x 的语法,所有旧的生命周期函数得到保留(除了 beforeDestroy 和 destroyed)
  • 当生命周期混合使用时:Vue3.x 的生命周期相对优先于 Vue2.x 的执行(比如:onMounted 比 mounted 先执行)
  • 这个 setup 执行时间位于 beforeCreate 和 created 之间,所以无法使用 data 和 methods(因为这两个都还没有初始化好)
  • 因为无法使用 data 和 methods 所以 Vue3 为了避免我们错误的使用,它将 this 修改成了 undefined
  • setup 函数只能是同步的,不能是异步的(就是不能在前面加 async)

Vue3 的生命周期钩子​

在Composition API中,我们需要先导入对应的生命周期钩子才能使用它。这么做,是为了让我们的项目尽可能的轻量化。

import { onMounted } from 'vue'

使用这些生命周期也和之前用法不太一样,现在都是在 setup 里面导入使用

import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured } from 'vue'

export default {
setup() {
onBeforeMount(() => {
// ...
})
onMounted(() => {
// ...
})
onBeforeUpdate(() => {
// ...
})
onUpdated(() => {
// ...
})
onBeforeUnmount(() => {
// ...
})
onUnmounted(() => {
// ...
})
onActivated(() => {
// ...
})
onDeactivated(() => {
// ...
})
onErrorCaptured(() => {
// ...
})
}
}

各个方法执行的时机​

onBeforeMount——挂载开始前调用 onMount——挂载后调用 onBeforeUpdate——当响应数据改变,且重新渲染前调用 onUpdated——重新渲染后调用 onBeforeUnmount——Vue实例销毁前调用 onUnmounted——实例销毁后调用 onActivated——当keep-alive组件被激活时调用 onDeactivated——当keep-alive组件取消激活时调用 onErrorCaptured——从子组件中捕获错误时调用

Update 钩子​

无论何时响应数据被修改,updated 生命周期事件都将触发,并且触发渲染更新。

beforeUpdate() and onBeforeUpdate()​

在数据修改且组件重渲染之前执行。这是任何更改还未发生前,手动修改 DOM 的好地方。beforeUpdate 对追踪组件的编辑次数时非常有用,甚至可以通过追踪对应的操作来创建一个 “撤销” 功能。

updated() and onUpdated()​

updated 方法在 DOM 更新后调用一次。

onUpdated 方法会在组件更新后调用,只有 data 里的变量改变并且要在页面重新渲染完成之后,才会进 updated 生命周期,只改变 data 里的值但是没有再页面上渲染该值的话并不会触发 updated 方法。

这是一段 beforeUpdate 和 updated 的基本代码

<template>
<div>
<p>{{val}} | edited {{ count }} times</p>
<button @click='val = Math.random(0, 100)'>Click to Change</button>
</div>
</template>

相对应的 script 代码

import { ref, onBeforeUpdate, onUpdated } from 'vue'

export default {
setup () {
const count = ref(0)
const val = ref(0)

onBeforeUpdate(() => {
count.value++;
console.log("beforeUpdate");
})

onUpdated(() => {
console.log("updated() val: " + val.value)
})

return {
count, val
}
}
}

这些方法很有用,但多数情况我们可能会通过监听器(watchers)去检测对应数据的改变。因为监听器可以很好的提供数据更改时的旧值和新值。

另一种方式是通过计算属性来改变元素的状态。

Destruction钩子(清理)​

destruction 钩子在组件被移除并需要清理一些待释放的功能时使用。这是删除事件监听并且防止内存溢出的好地方。

beforeUnmount() and onBeforeUnmounted()​

触发在组件开始销毁之前,在此会进行绝大多数的清理工作。在此阶段,你的组件仍然拥有所有的功能,任何东西都还未被销毁。

举一个删除事件监听的例子

 import { onMounted, onBeforeUnmount } from 'vue' 

export default {
setup () {

const someMethod = () => {
// do smth
}

onMounted(() => {
console.log('mount')
window.addEventListener('resize', someMethod);
})

onBeforeUnmount(() => {
console.log('unmount')
window.removeEventListener('resize', someMethod);
})

}
}

unmounted() and onUnmounted()​

此时,大多数组件和它的属性已经销毁,所以你能做的不多。同样,我打印一段数据去确切观察发生了什么。

import { onUnmounted } from 'vue'

export default {
setup () { /* Composition API */

onUnmounted(() => {
console.log('unmounted')
})

},
unmounted() { /* Options API */
console.log('unmounted')
}
}

Activation 钩子(管理Keep-Alive组件)​

keep-alive 标签是对动态组件的包装元素。它保存一段组件实例的缓存引用,如此 Vue 就不需要在每次动态组件(dynamic component)改变时创建一个新的实例。

对于这种特殊的使用情况,Vue提供了两个生命周期钩子。

activated() and onActivated()​

无论何时动态组件被 “重新激活”(意味着此时是动态组件激活视图)时该钩子方法都将被调用。

举个例子,如果我们使用 keep-alive 管理不同的 tab 视图,每次我们切换tab时,当前的tab将会触发activated钩子。

假设我们有以下用 keep-alive 包装的 动态组件 setup。

<template>
<div>
<span @click='tabName = "Tab1"'>Tab 1 </span>
<span @click='tabName = "Tab2"'>Tab 2</span>
<keep-alive>
<component :is='tabName' class='tab-area'/>
</keep-alive>
</div>
</template>

<script>
import Tab1 from './Tab1.vue'
import Tab2 from './Tab2.vue'

import { ref } from 'vue'

export default {
components: {
Tab1,
Tab2
},
setup () { /* Composition API */
const tabName = ref('Tab1')

return {
tabName
}
}
}
</script>

在我们的 Tab1.vue 组件中,我们能够如下访问 activation 钩子。

<template>
<div>
<h2>Tab 1</h2>
<input type='text' placeholder='this content will persist!'/>
</div>
</template>

<script>
import { onActivated } from 'vue'

export default {
setup() {
onActivated(() => {
console.log('Tab 1 Activated')
})
}
}
</script>

deactivated() and onDeactivated()​

和你想象的一样,视图不在动态组件中继续保持激活时触发此钩子。

该钩子在某些情况下非常有用,例如特定视图失去焦点时,保存用户数据和触发动画。

我们能够如下所示,捕获该生命周期钩子

import { onActivated, onDeactivated } from 'vue'

export default {
setup() {
onActivated(() => {
console.log('Tab 1 Activated')
})

onDeactivated(() => {
console.log('Tab 1 Deactivated')
})
}
}

现在,当我们切换 tab 时,每个动态组件的状态都将被保存。

Vue3 Debug Hooks​

Vue3 为我们提供了两个调试时的钩子:

  1. onRenderTracked
  2. onRenderTriggered

这两个事件都携带一个 DebuggerEvent 参数,以允许我们获悉是什么触发了 Vue 实例的重新渲染。

export default {
onRenderTriggered(e) {
debugger
// 检测什么依赖造成了组件的重新渲染
}
}

Reference​

参考自 【译】Vue3生命周期钩子(hooks)完整指南