第6章:组合式API
第16节:生命周期钩子与依赖注入
6.16.1 组合式API中的生命周期
在组合式API中,Vue 3提供了一系列函数来替代选项式API中的生命周期钩子。这些函数可以在组件的不同生命周期阶段执行。
生命周期钩子函数列表
| 选项式API | 组合式API | 说明 |
|---|---|---|
| beforeCreate | 无直接对应,使用setup() | 组件实例创建前 |
| created | 无直接对应,使用setup() | 组件实例创建完成 |
| beforeMount | onBeforeMount | 组件挂载前 |
| mounted | onMounted | 组件挂载完成 |
| beforeUpdate | onBeforeUpdate | 组件更新前 |
| updated | onUpdated | 组件更新完成 |
| beforeUnmount | onBeforeUnmount | 组件卸载前 |
| unmounted | onUnmounted | 组件卸载完成 |
| errorCaptured | onErrorCaptured | 捕获子组件错误 |
| renderTracked | onRenderTracked | 跟踪虚拟DOM渲染时的依赖 |
| renderTriggered | onRenderTriggered | 虚拟DOM重新渲染时触发 |
基本用法
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup() {
// 组件挂载后执行
onMounted(() => {
console.log('组件已挂载')
})
// 组件更新后执行
onUpdated(() => {
console.log('组件已更新')
})
// 组件卸载前执行
onBeforeUnmount(() => {
console.log('组件即将卸载')
})
// 组件卸载后执行
onUnmounted(() => {
console.log('组件已卸载')
})
// 捕获子组件错误
onErrorCaptured((err, instance, info) => {
console.error('捕获到子组件错误:', err, instance, info)
return false // 阻止错误继续传播
})
}
}在<script setup>中使用
<template>
<div>
<p>count: {{ count }}</p>
<button @click="count++">增加</button>
</div>
</template>
<script setup>
import { ref, onMounted, onUpdated, onUnmounted } from 'vue'
const count = ref(0)
onMounted(() => {
console.log('组件已挂载')
})
onUpdated(() => {
console.log('组件已更新')
})
onUnmounted(() => {
console.log('组件已卸载')
})
</script>生命周期钩子的执行顺序
- 组件实例创建 →
setup() - 组件挂载前 →
onBeforeMount() - 组件挂载完成 →
onMounted() - 数据更新 →
onBeforeUpdate() - 组件更新完成 →
onUpdated() - 组件卸载前 →
onBeforeUnmount() - 组件卸载完成 →
onUnmounted()
示例:使用生命周期钩子管理资源
<template>
<div>
<h3>定时器示例</h3>
<p>count: {{ count }}</p>
<button @click="stopTimer">停止定时器</button>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const count = ref(0)
let timer = null
onMounted(() => {
// 组件挂载后启动定时器
timer = setInterval(() => {
count.value++
}, 1000)
console.log('定时器已启动')
})
onUnmounted(() => {
// 组件卸载前清除定时器
if (timer) {
clearInterval(timer)
console.log('定时器已清除')
}
})
function stopTimer() {
if (timer) {
clearInterval(timer)
timer = null
console.log('定时器已手动停止')
}
}
</script>6.16.2 provide和inject依赖注入
provide和inject是Vue 3中用于实现组件间依赖注入的API。它们允许祖先组件向所有子孙组件提供数据,而不需要通过props一层一层传递。
基本用法
// 祖先组件
import { provide, ref } from 'vue'
export default {
setup() {
const location = ref('North Pole')
// 提供数据给子孙组件
provide('location', location)
return { location }
}
}
// 子孙组件
import { inject } from 'vue'
export default {
setup() {
// 注入祖先组件提供的数据
const location = inject('location', '默认值')
return { location }
}
}在<script setup>中使用
<!-- 祖先组件 App.vue -->
<template>
<div>
<h2>祖先组件</h2>
<p>位置: {{ location }}</p>
<button @click="location = 'South Pole'">更改位置</button>
<ChildComponent />
</div>
</template>
<script setup>
import { ref, provide } from 'vue'
import ChildComponent from './ChildComponent.vue'
const location = ref('North Pole')
// 提供数据
provide('location', location)
</script>
<!-- 子孙组件 GrandchildComponent.vue -->
<template>
<div>
<h3>子孙组件</h3>
<p>从祖先组件获取的位置: {{ location }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue'
// 注入数据
const location = inject('location', '默认位置')
</script>provide的注意事项
- provide可以提供任何类型的数据:包括基本类型、对象、函数等
- provide的数据会被所有子孙组件共享:任何子孙组件都可以注入并访问
- provide的数据默认是响应式的:如果提供的是响应式数据,子孙组件会自动更新
- provide可以在任何组件中使用:不仅限于根组件
6.16.3 响应式provide/inject
当provide提供响应式数据时,inject获取的数据也是响应式的,并且会自动更新。
示例:响应式依赖注入
<!-- 父组件 -->
<template>
<div>
<h2>主题设置</h2>
<select v-model="theme">
<option value="light">浅色主题</option>
<option value="dark">深色主题</option>
</select>
<ChildComponent />
</div>
</template>
<script setup>
import { ref, provide } from 'vue'
import ChildComponent from './ChildComponent.vue'
const theme = ref('light')
// 提供响应式主题数据
provide('theme', theme)
// 提供主题切换函数
provide('changeTheme', (newTheme) => {
theme.value = newTheme
})
</script>
<!-- 子组件 -->
<template>
<div :class="`theme-${theme}`">
<h3>子组件</h3>
<p>当前主题: {{ theme }}</p>
<button @click="changeTheme('light')">切换到浅色主题</button>
<button @click="changeTheme('dark')">切换到深色主题</button>
</div>
</template>
<script setup>
import { inject, computed } from 'vue'
// 注入主题数据
const theme = inject('theme', 'light')
// 注入主题切换函数
const changeTheme = inject('changeTheme', () => {})
</script>
<style>
.theme-light {
background-color: white;
color: black;
}
.theme-dark {
background-color: black;
color: white;
}
</style>只读注入数据
如果希望注入的数据是只读的,可以使用readonly函数包装:
import { provide, ref, readonly } from 'vue'
const count = ref(0)
// 提供只读的数据
provide('readonlyCount', readonly(count))注入时的类型安全
在TypeScript中,可以为注入的数据添加类型:
import { inject, Ref } from 'vue'
// 注入响应式数据并指定类型
const location = inject<Ref<string>>('location', ref('默认值'))
// 注入普通数据并指定类型
const appName = inject<string>('appName', '默认应用名')总结
Vue 3组合式API提供了一系列生命周期钩子函数和依赖注入API,使组件的生命周期管理和数据共享更加灵活。
- 生命周期钩子:使用
onMounted、onUpdated等函数替代选项式API中的生命周期钩子,可以在组件的不同阶段执行代码 - 依赖注入:使用
provide和inject实现组件间的数据共享,不需要通过props一层一层传递 - 响应式注入:
provide提供的响应式数据,inject获取后仍然保持响应性 - 类型安全:在TypeScript中可以为注入的数据添加类型,提高代码的安全性
在下一节中,我们将学习组合式API中的组合式函数(Composables),这是Vue 3中用于复用逻辑的重要特性。