Analyze the use method and principle of provide and inject of vue
- 2021-12-04 09:09:32
- OfStack
First of all, let's talk about why we use provide/inject. For communication between grandpa and grandson components, or even between grandpa and grandson components, we use vuex instead of ok.
That's true, but, please listen to me, sometimes your project is small and even there are few scenarios for component communication, so it is wasteful for you to introduce vuex just for a few communication parameters. Some people may also think of using
$parent
Get the parent component instance to get data/methods. This two-tier is fine. What about multi-tier components? If the components are nested deeply, what do you do? Write a function to put
$parent
Package 1 again. Isn't that very troublesome? You don't have to save the nation with curves. Haha ~ digress.
Don't talk so much nonsense, just tell you that using provide/inject is to solve your problems, which is absolutely true. Let's see how to use it. A backhand is just a few simple lines of code:
1. The parent component provides parameters to be passed to the child component
provide() {
return {
listType: this.listType,
}
}
2. Subcomponents use:
inject: ['listType'],
Of course, you can also specify your default values and the source of your parameters in inject:
inject:{
listType:{
from:"par"//provide The name of the definition
default:1
}
}
All right! Isn't it very simple? In fact, both parent and ancestor components can inject dependencies into descendant components, no matter how deep the component is.
Say one more:
provide can be either an object or a function that returns an object.
inejct: It can be an array of strings or an object.
If you are interested, look at the following source code section, which is also quite easy to understand:
provide core source code:
export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
if (!currentInstance) {
if (__DEV__) {
warn(`provide() can only be used inside setup().`)
}
} else {
// Object of the current component provides, The default instance inherits the parent class's provides Object
let provides = currentInstance.provides
// Use parent provide Object as a prototype to create your own provide Object
const parentProvides =
currentInstance.parent && currentInstance.parent.provides
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(parentProvides)
}
provides[key as string] = value
}
}
inject core source code:
export function inject(
key: InjectionKey<any> | string,
defaultValue?: unknown,
treatDefaultAsFactory = false
) {
// Gets the current component instance
const instance = currentInstance || currentRenderingInstance
if (instance) {
// Get provides
const provides =
instance.parent == null
? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
if (provides && (key as string | symbol) in provides) {
// If key If it exists, it will return directly
return provides[key as string]
} else if (arguments.length > 1) {
// If key Does not exist, if the default value is set, the default value will be returned directly
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue.call(instance.proxy)
: defaultValue
} else if (__DEV__) {
// If there is none, prompt
warn(`injection "${String(key)}" not found.`)
}
} else if (__DEV__) {
warn(`inject() can only be used inside setup() or functional components.`)
}
}