• provide/inject 依赖注入


    依赖注入

    在我们日常开发的过程中,我们需要从父组件向子组件传递数据,会使用 props

    如果组件层级过多,使用 props 沿着组件链逐级传递下去,十分的麻烦。

    而在 Vue 中使用 provideinject 来帮助我们解决这一问题。

    父组件可以为其所有的后代组件提供依赖,无论层级有多深。

    import { provide, inject } from "vue";
    
    • 1

    provide

    provide 可以提供一个值,可以被后代组件注入,它是一个后代组件依赖的提供者。

    // parent.vue
    import { provide } from "vue";
    
    provide("data", {
      name: "Buerjia",
      age: 23,
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    inject

    inject 用于声明 provide 提供的依赖。

    // chlid.vue
    import { inject } from "vue";
    const data = inject("data");
    
    console.log(data);
    // log
    // { name: "Buerjia", age: 23 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当父组件没有传入提供给我们相关依赖的情况下,我们还可以为 inject 设置默认值。

    // chlid.vue
    import { inject } from "vue";
    const data = inject("data", {
      name: "jack",
      age: 24,
    });
    
    console.log(data);
    // log
    // { name: "jack", age: 24 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    思考?

    在多人协作开发的项目中,我们很难确保 provide 提供的 key 保持唯一性,那么我们可以这么去解决它呢?

    使用 Symbol 作为注入名

    我们都知道 es6 中给我们提供了一个新的数据类型 Symbol ,代表着独一无二的值,我们可以将 Symbol 作为 key 值来比避免谈对协作中的命名冲突。

    // ./injectionSymbols.ts
    
    export const dataSymbol = Symbol();
    
    • 1
    • 2
    • 3
    // parent.vue
    import { provide } from "vue";
    import { dataSymbol } from "./injectionSymbols";
    
    provide(dataSymbol, {
      name: "Buerjia",
      age: 23,
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // child.vue
    import { inject } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    
    const data = inject(dataSymbol, {
      name: "jack",
      age: 24,
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    响应式的数据注入

    provide 提供的数据本身就是响应式的,我们只需要修改 provide 提供的数即可。

    // parent.vue
    import { ref, provide } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    import { dataRaw } from "../types/inject";
    
    const data = ref<dataRaw>({
      name: "",
      age: 18,
    });
    
    provide(dataSymbol, data.value);
    
    setTimeout(() => {
      data.value.name = "Mary";
    }, 3000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    当我在我们日常的业务场景中我们不仅仅通过父组件去更新状态,我们还需要通过子组件去更新状态。

    Vue 的官方推荐我们在创建 provide 的时候暴露给 inject 修改的状态的的方法。

    // parent.vue
    import { ref, provide } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    import { dataRaw } from "../types/inject";
    
    const data = ref<dataRaw>({
      name: "Buerjia",
      age: 18,
    });
    
    const updateData = (name: string) => {
      data.value.name = name;
    };
    
    provide(dataSymbol, {
      data: data.value,
      updateData,
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    // child.vue
    import { inject } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    
    const { data, updateData } = inject(dataSymbol, {
      data: {
        name: "Jack",
        age: 24,
      },
    });
    
    setTimeout(() => {
      updateData && updateData("Mary");
    }, 3000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    当然有些时候我们并不希望我们的数据被改变,我们使用使用 readonly() 来包装,当我们尝试修改时将会失败。

    // parent.vue
    import { ref, provide, readonly } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    import { dataRaw } from "../types/inject";
    
    const data = ref<dataRaw>({
      name: "Buerjia",
      age: 18,
    });
    
    provide(dataSymbol, readonly(data.value));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // child.vue
    import { inject } from "vue";
    import { dataSymbol } from "../injectionSymbols";
    
    const data = inject(dataSymbol, {
      name: "Jack",
      age: 24,
    });
    
    data.name = "Mary";
    // [Vue warn] Set operation on key "name" failed: target is readonly.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    为 provide/inject 添加类型

    provideinject 通常在不同组件中运行,所以我们需要为其添加类型支持。

    Vue 为我们提供了 InjectionKey 的类型接口,可以 provideinject 中同步注入值的类型。

    import { InjectionKey } from "vue";
    import { dataRaw } from "./types/inject";
    
    export const dataSymbol = Symbol() as InjectionKey<dataRaw>;
    
    • 1
    • 2
    • 3
    • 4

    总结

    provide/inject 依赖注入相比 props,极大的减少了依赖嵌套,使得代码更加的简洁并且利于维护,日常开发中要思考多加思考是否能够依赖注入解决问题。

  • 相关阅读:
    chromedriver依赖安装失败 解决办法
    架构每日一学 4:成为首席架构师,你必须学会顺应人性
    为什么MySQL的浮点数类型不够精准?(实例证明)
    理解3ds max 中的衰减贴图
    使用MATLAB进行傅里叶变换
    ps制作gif动图
    使用Vscode创建一个C_Hello程序
    【Qt炫酷动画】专栏导航目录
    无痛入门Prometheus:一个强大的开源监控和告警系统,如何快速安装和使用?
    win11无法打开chm格式的文件
  • 原文地址:https://blog.csdn.net/qq_39157944/article/details/126697833