In VUE, components communicate in various ways, such as props for parent component to transmit parameters to child component, Emit for child component to communicate with parent component, eventBus/(provides/inject) for sibling component to communicate. Now let’s explore the implementation of provide and Inject.

provide

In the development process, we often use provide in the parent component or higher component, and then use inject to accept in the descendant component. ProvideAPI in VUE brings great convenience to our development, and in the use process, The parent component does not need to know which descendant components are calling the current provide, and the descendant component does not need to know where the function that the current Inject calls comes from. Let’s take a look at the implementation of provideAPI in vue3 source code.

function provide<T> (key: InjectionKey<T> | string | number, value: T) {
  // Issue a warning in the development environment if the component currently provided does not exist ⚠️
  if(! currentInstance) {if (__DEV__) {
      warn(`provide() can only be used inside setup().`)}}else {
    let provides = currentInstance.provides
    const parentProvides =
      currentInstance.parent && currentInstance.parent.provides
    if (parentProvides === provides) {
      provides = currentInstance.provides = Object.create(parentProvides)
    }
    // TS doesn't allow symbol as index type
    // The parent component's provide overrides the root component's provide with the same key value
    provides[key as string] = value
  }
}
Copy the code

As you can see, the provide code is not very long compared to watchAPI, so let me walk you through it. As you can see from the code, the provide function does only one thing: it adds the currently passed function to the provides object. One thing to note here is that when you pass a provide in the root component, If the key value is the same, the provide passed in the parent overrides the provide in the root component, which is something to be aware of during development. Let’s take a look at the implementation of Inject.

inject

The provideAPI method puts all the received keys and values into a Provider object. Inject function is a function that calls the provider method

function inject(key: InjectionKey<any> | string, defaultValue? : unknown, treatDefaultAsFactory =false
) {
  // fallback to `currentRenderingInstance` so that this can be called in
  // a functional component
  const instance = currentInstance || currentRenderingInstance
  if (instance) {
    / / # 2400
    // to support `app.use` plugins,
    // fallback to appContext's `provides` if the intance is at root
    const provides =
      instance.parent == null
        ? instance.vnode.appContext && instance.vnode.appContext.provides
        : instance.parent.provides
    If the current function exists in the provides array, then the second argument exists. If the second argument exists, then the second argument is a function. If it is a function, then the function is called. Otherwise return the second argument and a warning if the second argument is not present
    if (provides && (key as string | symbol) in provides) {
      // TS doesn't allow symbol as index type
      return provides[key as string]
    } else if (arguments.length > 1) {
      return treatDefaultAsFactory && isFunction(defaultValue)
        ? defaultValue()
        : defaultValue
    } else if (__DEV__) {
      warn(`injection "The ${String(key)}" not found.`)}}else if (__DEV__) {
    warn(`inject() can only be used inside setup() or functional components.`)}}Copy the code

In inject function, this function takes three parameters. The first parameter is the provide method key, and the method corresponding to the current key value is called by providing. The second parameter is a default value, and the third parameter is an optional Boolean value.

  1. In this code, we check whether the current instance is the root component, and then check whether the function key exists in the provides. If so, we return the result of the function execution.
  2. The parameter treatDefaultAsFactory is more like a switch, which controls whether the second parameter is needed or not.
  3. If treatDefaultAsFactory is true and the second argument is a function, return the default value of the function, otherwise return the second argument.
  4. A warning is returned if the above conditions are not met.

How, after watching is not feel provide very simple 😄.

This code is located at packake/ Runtime-core/SRC/apiinject.ts. Take a look if you’re interested.