一、inject 和provide 的用法
inject 和 provide 是 Vue 3 中的依赖注入机制,用于在组件树中传递数据,而不需要通过 props 逐级传递
1. 基本用法
// 父组件
import { provide } from 'vue'
const message = ref('Hello')
provide('key', message)
// 子组件
import { inject } from 'vue'
const message = inject('key')
2. 使用 Symbol 作为 key(推荐)
// types.ts
export const MESSAGE_KEY = Symbol()
// 父组件
import { MESSAGE_KEY } from './types'
provide(MESSAGE_KEY, message)
// 子组件
import { MESSAGE_KEY } from './types'
const message = inject(MESSAGE_KEY)
3. 提供默认值
const message = inject('key', '默认值')
4. 类型声明:
interface MessageContext {
message: Ref<string>
updateMessage: (value: string) => void
}
// 父组件
provide<MessageContext>('messageContext', {
message,
updateMessage: (value) => { message.value = value }
})
// 子组件
const { message, updateMessage } = inject<MessageContext>('messageContext')!
5. 只读数据
import { readonly } from 'vue'
provide('count', readonly(count))
二、注意事项
- provide 和 inject 绑定不是响应式的。但如果你传递了一个响应式对象,那么它的属性仍然是响应式的。
- 尽量在 setup() 函数中使用 provide 和 inject。
- 不要在子组件中修改注入的值,除非父组件明确允许。
- 使用 Symbol 作为 key 可以避免命名冲突。
- 考虑使用 TypeScript 来增强类型安全。
- 使用 provide 和 inject 可以简化组件间的数据传递,特别是对于深层嵌套的组件结构。但也要注意不要过度使用,以免使数据流变得难以追踪。
三、案例代码
要实现点击 tab 获取最新的 sessionStorage.getItem('activeTabType'),可以按以下步骤修改代码:
-
修改 getActiveTabType 计算属性
const getActiveTabType = computed(() => {
return sessionStorage.getItem('activeTabType') || '';
}); -
在 AggregateAnalysisTab(子组件) 组件中,当 tab 被点击时,更新 sessionStorage:
// 在 AggregateAnalysisTab.vue 中
const handleTabClick = (tabType: string) => {
sessionStorage.setItem('activeTabType', tabType);
}; -
在父组件中添加一个响应式变量来触发重新计算:
const tabUpdateTrigger = ref(0);
const getActiveTabType = computed(() => {
tabUpdateTrigger.value; // 添加这行来依赖这个变量
return sessionStorage.getItem('activeTabType') || '';
}); -
使用 provide/inject 或事件总线在 AggregateAnalysisTab 中通知父组件更新:
// 在父组件中
provide('updateTabType', () => {
tabUpdateTrigger.value++;
});// 在 AggregateAnalysisTab.vue 中
const updateTabType = inject('updateTabType');const handleTabClick = (tabType: string) => {
sessionStorage.setItem('activeTabType', tabType);
updateTabType();
};
这样,每次点击 tab 时,sessionStorage 会被更新,并且父组件的 getActiveTabType 计算属性会重新计算,获取最新的值。
四、类型问题
如: "updateTabType"的类型为"未知"
-
在父组件中定义 updateTabType 的类型:
type UpdateTabType = () => void;
// 在父组件中
const updateTabType: UpdateTabType = () => {
tabUpdateTrigger.value++;
};provide('updateTabType', updateTabType);
-
在 子组件 AggregateAnalysisTab.vue 中,我们可以这样使用 inject:
import { inject } from 'vue';
type UpdateTabType = () => void;
const updateTabType = inject('updateTabType') as UpdateTabType;