Vue3 - provide和inject
在 Vue 中,provide 和 inject 是一对用于跨层级组件通信的 API,用于解决父子组件、祖孙组件甚至更深层次组件之间的数据传递问题,避免了通过 props 逐层传递的繁琐(“props drilling”)。
核心作用
provide:在父组件(或祖先组件) 中定义需要传递给后代组件的数据或方法。inject:在子组件(或后代组件) 中接收祖先组件通过provide提供的数据或方法。
无论组件层级多深,只要是在同一个组件树中,inject 都能拿到 provide 提供的值。
基本用法
1. 祖先组件使用 provide 提供数据
<!-- 祖先组件 Ancestor.vue -->
<script setup>
import { provide, ref } from 'vue'
// 提供静态数据
provide('siteName', 'Vue 示例')
// 提供响应式数据(用 ref 包装)
const user = ref({ name: '张三', age: 20 })
provide('currentUser', user)
// 提供方法(可用于修改数据)
const updateUser = (newName) => {
user.value.name = newName
}
provide('updateUser', updateUser)
import Descendant from './componets/Descendant.vue'
</script>
<template>
<Descendant></Descendant>
</template>
2. 后代组件使用 inject 接收数据
<!-- 后代组件 Descendant.vue(可以是子组件、孙组件等) -->
<script setup>
import { inject } from 'vue'
// 接收静态数据(第二个参数是默认值,可选)
const siteName = inject('siteName', '默认名称')
// 接收响应式数据(拿到的是 ref 对象,需要 .value 访问)
const currentUser = inject('currentUser')
// 接收方法
const updateUser = inject('updateUser')
</script>
<template>
<div>
<p>网站名称:{{ siteName }}</p>
<p>用户名:{{ currentUser?.name }}</p>
<button @click="updateUser('李四')">修改用户名</button>
</div>
</template>
关键特性
-
响应式支持:
如果
provide提供的是ref或reactive类型的响应式数据,inject接收后仍能保持响应式。当数据变化时,所有使用该数据的后代组件都会自动更新。<!-- 祖先组件中修改数据 --> <button @click="user.age++">增加年龄</button> <!-- 后代组件会自动显示最新年龄 --> -
默认值处理:
inject的第二个参数是默认值,当祖先组件没有提供对应 key 时,会使用默认值。如果默认值是一个对象,建议用工厂函数返回,避免多个组件共享同一个对象实例:// 推荐:用工厂函数返回默认对象(每次注入都会创建新对象) const config = inject('appConfig', () => ({ theme: 'light' })) -
类型提示(TS):
在 TypeScript 中,可以通过泛型指定
inject的类型,增强类型安全性:const user = inject<{ name: string; age: number }>('currentUser', { name: '', age: 0 }) -
全局提供(应用级别):
可以在创建 Vue 应用时通过
app.provide()提供全局数据,所有组件都能注入:// main.js import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.provide('appVersion', '1.0.0') // 全局提供 app.mount('#app')
注意事项
-
避免过度使用:
provide/inject打破了组件的封装性(后代组件依赖祖先组件的数据,但无法从组件 props 中明确看出依赖关系),建议仅在跨多层级通信时使用,简单的父子组件通信优先用props/emits或ref引用。 -
数据修改原则:
建议在提供数据的组件中定义修改方法(如上述
updateUser),后代组件通过调用方法修改数据,而不是直接修改inject拿到的响应式数据,这样便于追踪数据变化。 -
key 的唯一性:
provide的 key 是字符串,需确保全局唯一(尤其在多人协作时),避免命名冲突(可使用 Symbol 作为 key 解决):// 定义唯一 key export const key = Symbol('user') // 祖先组件 provide(key, user) // 后代组件 inject(key)
适用场景
- 主题切换(全局主题配置需要传递给所有组件)。
- 用户登录状态(多个组件需要获取当前用户信息)。
- 全局配置(如 API 基础地址、权限配置等)。
通过 provide 和 inject,可以优雅地实现跨层级组件通信,减少代码耦合。
更多推荐
所有评论(0)