Vue中的依赖注入实现机制
2021-10-26
| 2023-2-19
0  |  0 分钟
password
Created
Feb 19, 2023 03:50 PM
type
Post
status
Published
date
Oct 26, 2021
slug
summary
Vue中的依赖注入实现机制
tags
Vue
Vue源码
category
源码
icon
依赖注入是Vue中重要的, 解决跨多层级组件传值的方式之一. 与React中的Provider具有类似的效果

Vue2中的依赖注入

 // 在其上(N)层组件中提供一个provide函数  export default {    provide: function() {      return {        foo: this.foo     }   }  }    // 在子孙组件中进行注入  export default {    inject: ['foo']  }

Vue3中的依赖注入

Vue3中除了直接使用与Vue2相同的语法外, 还支持Hook化的依赖注入声明方式
 // provider  import { provide, ref } from 'vue'  export default {    setup() {      const theme = ref('dark')      provide('theme', theme)   }  }  // inject  import { inject } from 'vue'  export default {    setup() {      // inject支持第二个参数, 作为依赖注入的默认值      const theme = inject('theme', 'light')      return {        theme     }   }  }

provide API

provide可以被其上级任意一个组件提供, 实例创建的时候, 会使用其最邻近上级的provide的值.
也就意味着, 即使同一个provide的key被定义多次, 组件只会以其最近的父节点值为准
 function provide(key, value) {    let provides = currentInstance.provides    const parentProvides = currentInstance.parent && currentInstance.parent.provides    if (parentProvides === provides) {      provides = currentInstance.provides = Object.create(parentProvides)   }    provides[key] = value  }    // 在实例创建过程中, 将provides对象指向父组件实例的provides对象  const instance = {    // ...    provides: parent ? parent.provides : Object.create(appContext.provides)    // ...  }

inject API

 function inject(key, defaultValue) {    const instance = currentInstance || currentRenderingInstance    if (instance) {      const provides = instance.provides      // 能够从父级找到provide, 且有对应的key, 返回该value      if (key in provides) {        return provides[key]      // 否则, 如果有默认值, 就返回这个默认值     } else if (arguments.length > 1) {        return defaultValue      // 否则, 如果是非正式环境, 抛出找不到的警告     } else if ((process.env.NODE_ENV !== 'production')) {        // throw warn     }   }  }

为何要用依赖注入?

乍一看过去, 其实依赖注入的机制完全可以通过定义一个数据变量, 然后不同组件之间引用和修改的方式来进行啊, 那依赖注入的机制的意义何在呢?
这里其实主要有这几点:
  1. 直接使用全局数据的话数据的可溯性差, 如果使用全局数据, 我们并不知道这个数据在哪里被修改.
  1. 依赖注入只作用在该组件的子孙...组件中, 并没有影响到其他的组件
  1. 依赖注入饿后代组件并不需要知道注入的数据来自哪里, 只需要注入并使用即可. 而对于定义变量引入的方式来说, 我们需要知道它是在哪里被定义的, 才能够引入它
但是, 这里随之衍生的问题是: 祖先组件并不知道有哪些组件使用了它提供的数据, 后代组件也不需要知道注入的数据来自哪里. 虽然这是一种很好的解耦机制, 但是相互不知, 这里就有可能会产生混乱
因此, 一般来讲, 建议在公共类库中进行使用, 但业务的组件中则并不推荐使用, 业务共享可以考虑使用Pinia等状态管理工具来实现
源码
  • Vue
  • Vue源码
  • Vue中指令的实现机制Vue中组件的生命周期实现机制
    目录