问题:子孙组件如何共享数据
-
vue2.x
提供provide
选项
// Provider
export default {
provide: function () {
return {
foo: this.foo
}
}
}
// Consumer
export default {
inject: ['foo']
}
-
vue3.0
可以使用provide API
// Provider
import { provide, ref } from 'vue'
export default {
setup() {
const theme = ref('dark')
provide('theme', theme)
}
}
// Consumer
import { inject } from 'vue'
export default {
setup() {
const theme = inject('theme', 'light')
return {
theme
}
}
}
- 祖先组件不需要知道哪些后代组件在使用它提供的数据
- 后代组件也不需要知道注入的数据来自哪里
provide API 的实现原理
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 对象
- 组件实例的 provides 继承它的父组件
- 在
inject
阶段,我们可以非常容易通过原型链查找来自直接父级提供的数据 - 注意:
- 组件实例提供和父级
provides
中有相同key
的数据,是可以覆盖父级提供的数据
- 组件实例提供和父级
inject API实现原理
function inject(key, defaultValue) {
const instance = currentInstance || currentRenderingInstance
if (instance) {
const provides = instance.provides
if (key in provides) {
return provides[key]
}
else if (arguments.length > 1) {
return defaultValue
}
else if ((process.env.NODE_ENV !== 'production')) {
warn(`injection "${String(key)}" not found.`)
}
}
}
-
inject
支持两个参数- 第一个参数是
key
:我们可以访问组件实例中的 provides 对象对应的 key,层层查找父级提供的数据 - 第二个参数是默认值,如果查找不到数据,则直接返回默认值
- 第一个参数是
provide/inject共享数据与export共享数据
作用域
- 依赖注入
- 它的作用域是局部范围
- 不是这棵子树上的组件是不能访问到该数据的
- 模块化
- 作用域是全局范围
- 可以在任何地方引用它导出的数据
数据来源
- 依赖注入
- 后代组件是不需要知道注入的数据来自哪里,只管注入并使用即可
- 模块化
- 用户必须明确知道这个数据是在哪个模块定义的
上下文
- 依赖注入
- 提供数据的组件的上下文就是组件实例
- 同一个组件定义是可以有多个组件实例的,我们可以根据不同的组件上下文提供不同的数据给后代组件
- 模块化
- 没有任何上下文