Vue3 + TypeScript中provide和inject的用法示例
基础写法(类型安全)
typescript
// parent.component.vue import { provide, ref } from 'vue' import type { InjectionKey } from 'vue'// 1. 定义类型化的 InjectionKey const COUNTER_KEY = Symbol() as InjectionKey<number> const USER_KEY = Symbol() as InjectionKey<{ name: string }>// 在 setup 中使用 setup() {const counter = ref(0)provide(COUNTER_KEY, counter) // 提供响应式数据const user = { name: 'John' }provide(USER_KEY, user) // 提供静态对象return { counter } }
typescript
// child.component.vue import { inject } from 'vue' import type { InjectionKey } from 'vue'// 复用相同的 key const COUNTER_KEY = Symbol() as InjectionKey<number> const USER_KEY = Symbol() as InjectionKey<{ name: string }>setup() {// 2. 安全注入(带默认值)const counter = inject(COUNTER_KEY, ref(0)) // 响应式数据const user = inject(USER_KEY, { name: 'Guest' }) // 静态数据// 3. 强制注入(当确定父级已提供时)const forcedCounter = inject(COUNTER_KEY)!return { counter, user } }
<script setup>
语法糖写法
vue
<!-- Parent.vue --> <script setup lang="ts"> import { provide, ref } from 'vue'// 定义 key const messageKey = Symbol() as InjectionKey<string>const message = ref('Hello from parent') provide(messageKey, message) </script>
vue
<!-- Child.vue --> <script setup lang="ts"> import { inject } from 'vue'const messageKey = Symbol() as InjectionKey<string>// 注入 + 类型声明 const message = inject(messageKey, 'default message')// 处理可能 undefined 的情况 const safeMessage = inject(messageKey) ?? 'fallback value' </script>
响应式对象注入
typescript
// types.ts export interface User {id: numbername: string }export const UserKey = Symbol() as InjectionKey<User>
vue
<!-- Parent.vue --> <script setup lang="ts"> import { provide, reactive } from 'vue' import { UserKey } from './types'const user = reactive({id: 1,name: 'Alice' })provide(UserKey, user) </script>
vue
<!-- Child.vue --> <script setup lang="ts"> import { inject } from 'vue' import { UserKey } from './types'const user = inject(UserKey)// 使用时需要处理可能 undefined 的情况 if (user) {console.log(user.name) // 类型安全 } </script>
最佳实践提醒:
-
使用
InjectionKey
:确保类型安全 -
默认值处理:
inject(key, defaultValue)
-
响应式数据:建议使用
ref
/reactive
保持响应性 -
代码组织:推荐将 keys 集中管理在单独文件中
-
安全判断:当不确定是否已提供时,使用可选链操作符
?.
typescript
// 推荐的文件结构 // src/provides/keys.ts import type { InjectionKey } from 'vue'export const API_KEY = Symbol() as InjectionKey<AxiosInstance> export const THEME_KEY = Symbol() as InjectionKey<'light' | 'dark'>
typescript
// 祖先组件
// 提供函数给后代,获取受理样品选集
provide("provideApplySampleSelection", handleApplySampleSelectionChange);// 获取受理样品表格勾选的行数据
const handleApplySampleSelectionChange = (newSelection: ApplySample[]) => {//获取勾选行数据applySampleTableSelection.value = newSelection;// 控制按钮编辑状态buttonDisabled();
};// 后代组件
// 注入祖先提供的函数
const sendApplySampleSelection = inject("provideApplySampleSelection", (data: ApplySample[]) => {});// 获取受理样品表格勾选的行数据
const handleApplySampleSelectionChange = (newSelection: ApplySample[]) => {// 向祖先组件发送表格选集sendApplySampleSelection(newSelection);
};