問題:子孫組件如何共享數(shù)據(jù)
-
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
}
}
}
- 祖先組件不需要知道哪些后代組件在使用它提供的數(shù)據(jù)
- 后代組件也不需要知道注入的數(shù)據(jù)來自哪里
provide API 的實現(xiàn)原理
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
}
- 創(chuàng)建組件實例的時候,組件實例的 provides 對象指向父組件實例的 provides 對象
- 組件實例的 provides 繼承它的父組件
- 在
inject階段,我們可以非常容易通過原型鏈查找來自直接父級提供的數(shù)據(jù) - 注意:
- 組件實例提供和父級
provides中有相同key的數(shù)據(jù),是可以覆蓋父級提供的數(shù)據(jù)
- 組件實例提供和父級
inject API實現(xiàn)原理
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支持兩個參數(shù)- 第一個參數(shù)是
key:我們可以訪問組件實例中的 provides 對象對應(yīng)的 key,層層查找父級提供的數(shù)據(jù) - 第二個參數(shù)是默認值,如果查找不到數(shù)據(jù),則直接返回默認值
- 第一個參數(shù)是
provide/inject共享數(shù)據(jù)與export共享數(shù)據(jù)
作用域
- 依賴注入
- 它的作用域是局部范圍
- 不是這棵子樹上的組件是不能訪問到該數(shù)據(jù)的
- 模塊化
- 作用域是全局范圍
- 可以在任何地方引用它導出的數(shù)據(jù)
數(shù)據(jù)來源
- 依賴注入
- 后代組件是不需要知道注入的數(shù)據(jù)來自哪里,只管注入并使用即可
- 模塊化
- 用戶必須明確知道這個數(shù)據(jù)是在哪個模塊定義的
上下文
- 依賴注入
- 提供數(shù)據(jù)的組件的上下文就是組件實例
- 同一個組件定義是可以有多個組件實例的,我們可以根據(jù)不同的組件上下文提供不同的數(shù)據(jù)給后代組件
- 模塊化
- 沒有任何上下文