provide/inject basic usage
In Vue.js
, if a cross-level component wants to pass data, we can directly use props
to pass the data of the ancestor component to the descendant component:
Note: The picture above is from Vue.js
official website: Prop Drilling .
As shown above, the intermediate component <Footer>
may not need this part at all props
, but in order to <Footer>
<DeepChiild>
can access these props
, <Footer>
still need to define these props
and pass it on.
Some people say that we can use $attrs/$listeners
, but we still have to go through the middle level, and using Vuex
is too troublesome, and Event Bus
can easily lead to logical dispersion and problems difficult to locate.
So, is there any other way to pass data directly from ancestor component to descendant component? The answer is provide/inject
.
Ancestor component:
// Root.vue
<script setup>
import { provide } from 'vue'
provide('msg' /* 注入的键名 */ , 'Vue.js' /* 值 */)
</script>
Descendant components:
// DeepChild.vue
<script setup>
import { inject } from 'vue'
const msg = inject('msg' /* 注入的键名 */, 'World' /* 默认值 */)
</script>
For specific usage, see: Provide / Inject .
Now, the problem is solved:
Note: The above picture is from Vue.js
official website: Prop Drilling .
provide implementation principle
How is such a miraculous thing achieved?
export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
let provides = currentInstance.provides
const parentProvides = currentInstance.parent && currentInstance.parent.provides
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(parentProvides)
}
provides[key as string] = value
}
By default, a component instance's provides inherit from its parent component. But when a component instance needs to provide its own value, it uses the parent component's provides object as a prototype to create its own provides object. In this way, when using inject
, we can find the data provided by the parent component through the prototype chain .
inject implementation principle
The code of inject
is also very simple, so simple that you will come to a sentence after reading it:
export function inject(
key: InjectionKey<any> | string,
defaultValue?: unknown,
treatDefaultAsFactory = false
) {
const instance = currentInstance || currentRenderingInstance
if (instance) {
// #2400
// to support `app.use` plugins,
// fallback to appContext's `provides` if the instance is at root
const provides = instance.parent == null
? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
if (provides && (key as string | symbol) in provides) {
return provides[key as string]
} else if (arguments.length > 1) {
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue.call(instance.proxy)
: defaultValue
}
}
}
inject
has two main functions:
- Through the
in
operation to obtain the data of the parent component, thein
operation will traverse the prototype chain, which is the implementation of the aboveprovide
, why the component uses the provides of the parent component Objects are used as prototypes to create their own provides objects - Implement the default value function of
inject
1996bba74102f3d5193d33fd230f04d4---,inject
The second parameter is the default value
One sentence summary: provide/inject
Use the prototype chain to realize data transfer across hierarchical components.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。