在Vue 3中,provide
和inject
API是一种非常强大的功能,用于在组件层级之间传递数据,特别是在处理深层嵌套组件时非常有用。它们允许开发者跨越多个组件层级直接传递数据,而不需要通过每个层级逐层传递props。
在祖先组件中提供数据(provide)
你可以在祖先组件中使用provide
来定义要共享的数据。这通常在setup
函数中完成。
import { provide, ref } from 'vue';
export default {
setup() {
const sharedData = ref('some data');
// 提供数据
provide('key', sharedData);
// ...
}
}
在这个例子中,我们提供了一个名为key
的数据,其值为sharedData
。
在后代组件中注入数据(inject)
在需要接收数据的子孙组件中,你可以使用inject
来接收这些数据。
import { inject } from 'vue';
export default {
setup() {
// 注入数据
const sharedData = inject('key');
// 使用sharedData
// ...
return {
sharedData
};
}
}
在这个例子中,我们注入了之前由祖先组件提供的名为key
的数据。
唯一键:provide
和inject
使用一个唯一的标识符(在上面的例子中是'key'
)来配对提供者和接收者。这个键可以是字符串或Symbol。
响应性:如果你希望提供的数据是响应式的,你应该使用ref
或reactive
来创建这些数据。
默认值:inject
函数接受第二个可选参数作为默认值,当无法找到提供的数据时将使用这个默认值。
作用域:provide
和inject
主要用于跨组件通信,它们不应该被用来替代组件的正常props和events通信模式。
假设你正在构建一个应用,其中有一个深层嵌套的组件结构,你需要在顶层组件中设置一个主题(如颜色主题),并且希望所有子组件都能访问到这个设置。使用provide
和inject
可以轻松地实现这一功能,而不需要在每个中间组件中传递props。
provide
和inject
的这种使用方式有助于保持组件接口的清洁和简单,同时提供一种强大的跨组件通信机制。
在Vue2.x中,provide和inject是单向数据流,即子组件通过inject获取父组件provid的变量,但是子组件修改后并不能反向影响到父组件。而在Vue3.x中,我们可以通过使用reactive和toRef将provide的数据变成响应式的,实现provide和inject的双向绑定。
// Parent组件
import { reactive, toRef } from 'vue';
export default {
setup() {
const state = reactive({ count: 0 });
// 暴露出count及其响应式引用
provide('count', { count: state.count, countRef: toRef(state, 'count') });
return { state };
},
};
// Child组件
import { inject } from 'vue';
export default {
setup() {
// inject暴露出来的对象包含count及其响应式引用
const { count, countRef } = inject('count');
function add() {
countRef.value++;
}
return { count, add };
},
};
高阶用法:
const SharedStateSymbol = Symbol();
export { SharedStateSymbol };
在提供者中:
import { provide, ref } from 'vue';
import { SharedStateSymbol } from './symbols';
export default {
setup() {
const sharedState = ref({ counter: 0 });
provide(SharedStateSymbol, sharedState);
// ...
}
}
在注入者中:
import { inject } from 'vue';
import { SharedStateSymbol } from './symbols';
export default {
setup() {
const sharedState = inject(SharedStateSymbol);
// ...
return {
sharedState
};
}
}
provide
和inject
也可以在组合函数(Composition Functions)中使用,这使得你可以创建可重用的逻辑片段。
// useSharedState.js
import { provide, ref, inject } from 'vue';
const SharedStateSymbol = Symbol();
export function provideSharedState() {
const sharedState = ref({ counter: 0 });
provide(SharedStateSymbol, sharedState);
}
export function useSharedState() {
const sharedState = inject(SharedStateSymbol);
if (!sharedState) {
throw new Error('No provided shared state!');
}
return sharedState;
}
当使用TypeScript时,你可以为提供和注入的数据提供类型注解,以增加类型安全性。
import { provide, inject, ref, Ref } from 'vue';
interface SharedState {
counter: number;
}
const SharedStateSymbol: InjectionKey> = Symbol();
export default {
setup() {
const sharedState: Ref = ref({ counter: 0 });
provide(SharedStateSymbol, sharedState);
// ...
}
}
// 在子组件中
export default {
setup() {
const sharedState = inject(SharedStateSymbol);
if (!sharedState) {
throw new Error('sharedState is not provided');
}
// ...
return {
sharedState
};
}
}
这些高阶用法能够让你更有效地在Vue应用中管理跨组件的状态和逻辑,同时保持代码的可维护性和可扩展性。