Vue3 依赖注入 - Provide/Inject

3,119 阅读3分钟

Vue3 依赖注入 - Provide/Inject

对于父子组件通信,我们可以使用props来传递数据,但是对于多层级嵌套的组件,我们要向更深层的子组件传递数据,props就完成不了。

Vue3中提供了两个新的api,provide()inject(),就是用来解决跨代组件通信的问题。并且还可以向全局中注入数据。

provide()向组件中注入数据,inject()获取注入的数据。 一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

1.基本使用

在父组件中注入数据:provide()

//父组件中注入
provide("key", "value");

子组件中获取数据:inject()

//子组件/隔代组件中获取
const inject1 = inject<string>("key");

2.注入响应式数据

provide()能够注入任意的数据,当然也包括响应式数据。不同于props的单向数据流,provide()注入的是真的响应式数据。可以在父组件中修改,也可以在子组件中进行修改,都是响应式的,因为操作的都是同一个响应式对象。

父组件注入:

interface Person {
   name: string,
   age: number
}

const person: Person = reactive({
   age: 18,
   name: "tom"
})
provide<Person>("key", person)

//父组件修改数据
setTimeout(() => {
   person.name = "cat";
},3000)

子组件获取:

const inject1 = inject<Person>("key");

//子组件修改数据
if (inject1 != undefined) {
   inject1.name = "dog";
}

子组件的 inject1 和父组件的person是同一个对象。

3. 使用 Symbol 作注入名

在项目中,会有非常多的注入数据,建议最好使用 Symbol 来作为注入的key避免冲突。

定义:

新建一个keys.ts文件,将要注入的key名都在这个文件中进行定义,这样会便于我们管理和使用。

//keys.ts中
export interface Person {
    name: string,
    age: number
}

export const key = Symbol() as InjectionKey<Person>;//标注类型。

​ 在定义的Symbol key时使用Vue3提供的InjectionKey接口来为注入的数据标记类型,这样在注入数据的时候,就能进行类型检查,在获取的时候返回的就是定义的类型,不用通过泛型去接受或者强转。

父组件中注入:

import {key, Person} from "./commonTs/keys";
const person: Person = reactive({
   age: 18,
   name: "tom"
});
provide(key, person)//在使用的时候会检查传入的类型。

子组件中获取:

import {key} from "../commonTs/keys";
const inject1 = inject(key);//获取的时候,返回的就是标识的类型。

因为使用InjectionKey标记类型,返回值的类型就是key指定的类型,所有可以不用指定泛型来使用。

4. 注入全局数据

可以在main.js通过vue实例去注入全局的数据。是不是和Vuex很像?

main.js中注入:

import {key, Person} from "./commonTs/keys";

const app = createApp(App);
const person: Person = reactive({
    age: 0,
    name: "cat"
})
app.provide(key, person)
app.mount('#app');

组件中获取使用:

import {key} from "./commonTs/keys";
const inject1 = inject(key);

注意:注入的数据必须在实例挂载之前进行注,否则获取到的数据都是undefined

错误注入全局数据:

app.mount('#app');//实例挂载
app.provide(key, person)

正确注入全局数据:

app.provide(key, person)
app.mount('#app');