Provide and Inject can transfer values between parent and child components. Compared with PROP, Provide and Inject are more convenient and lighter than VUEX.

Next, we will introduce Provide and Inject in terms of usage and implementation principles.

ProvideandInjectThe use of

Summary: The parent component uses a provide function to provide data, while the child component uses the Inject function to get data.

provide APIThe use of

We’ll use the official example here. Those who have read the official example can skip this section.

  • You need to follow the instructions before usingvueReferenced in theprovidefunction
import { provide } from "vue";
Copy the code

With the plug-in, the editor (such as VS Code) can automatically import this function after the provide Code is typed, instead of manually importing it. This is just for illustration.

  • insetupCall from a functionprovideFunction provides data
<! -- grandparent.vue --> setup() {// omit other... Provide ('location', 'North Pole ') provide('geolocation', {longitude: 90, latitude: 135})}Copy the code

Provide takes two parameters: the first parameter represents a string key; The second argument is value, which can be an object or a common data type.

inject APIThe use of
  • You need to follow the instructions before usingvueReferenced in theinjectfunction
import { inject } from "vue";
Copy the code
  • insetupCall from a functioninjectFunction fetch data
<! -- GrandSon --> setup() {// leave out other... const userLocation = inject('location', 'The Universe') const userGeolocation = inject('geolocation') },Copy the code

Inject also has two parameters: the first parameter represents the key to be obtained; The second argument is the default (optional) value to be filled in when key is not in value. If the default value is not set, the value is undefined.

forprovideAdd responsiveness

Add responsiveness indicates that when the data provided by provide changes, the interface of the component that uses data needs to be refreshed. We figured we’d definitely need some responsive apis for Vue3.0.

  • The modifiedprovideIt looks like this:
<! -- grandparent.vue --> setup() {// omit other... Provide ('location', ref(' arctic ')) provide('geolocation', reactive({longitude: 90, latitude: 135})}Copy the code
  • injectThere is no difference in the use of, but ifinjectIs used in the component templateprovideThe component will perform a UI refresh in a timely manner.

ProvideandInjectPrinciple analysis of

The value of

  • Component instance objectComponentInternalInstanceThere is aprovidesProperties;
<! -- components.ts --> export interface ComponentInternalInstance { ** * Object containing values this component provides for its descendents * @internal */ provides: Data }Copy the code
  • When creating a component instance object,providesProperty will point to the parent component instance objectprovidesProperties;
export function createComponentInstance( vnode: VNode, parent: ComponentInternalInstance | null, suspense: SuspenseBoundary | null) {const instance: ComponentInternalInstance = {/ / omit other properties... provides: parent ? parent.provides : Object.create(appContext.provides), } return instance }Copy the code

The provides for the root instance Object is Object.create(null), which is the pure empty Object {}.

When all components do not use the provide function, the effect looks like this:

  • Called in the component instanceprovideFunction, will be the parent componentprovidesMake a copy of the template for the current componentprovidesThat no longer points to the parent componentprovides, but willprovideIn thekeyandvalueCorresponding to save;
export function provide<T>(key: InjectionKey<T> | string | number, value: T) { let provides = currentInstance.provides const parentProvides = currentInstance.parent && CurrentInstance. Parent. Provides / / if points to the parent component ` provides ` object is a copy if (parentProvides = = = provides) {provides = Currentinstance. provides = object. create(parentProvides)} // Save 'provide' 'key' and 'value' to provide [key as string] = value }Copy the code

When a component uses the provide function, the effect looks like this:

If the parent and child component provide functions use the same key to provide data, what value does their common child component get by the inject function?

Answer: Clearly the value provided by the provide of the nearest parent component to the component itself.

  • injectFunction logic is very simple, is to take the current component instanceprovidesObject corresponding to thekeythevalueIf you don’t get itvalueI’ll just use the defaultsdefaultValueIf there is no default valuedefaultValueAs a result,undefined;
function inject(key, defaultValue, treatDefaultAsFactory = false) { const instance = currentInstance || currentRenderingInstance; If (instance) {// Provides = instance. Parent == null? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides; if (provides && key in provides) { return provides[key]; } else if (arguments.length > 1) { return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance.proxy) : defaultValue; }}}Copy the code

responsive

This logic does not need to be analyzed too much, and is no different from declaring a reactive data in this component, refer to the previous article. Reactive data changes trigger a component’s side effect rendering function to update the UI.

ProvideandInjectThe defects of

In the case of Provide and Inject value transmission, parent and child components are independent of each other, that is, parent components do not care whether any child components use the data provided by them, and child components do not know which parent component data comes from.

Data isolation, but will result in a high degree of coupling at the component level, for example, the child (grandson) component must provide data corresponding to the parent (parent) component for normal operation. Otherwise, it will not function properly.

Therefore, Provide and Inject are more suitable for use in function libraries (scenarios where components are already highly coupled) rather than in large projects.