头图

Understand the vuex4 source code in one article, so provide/inject is the magical use of the prototype chain?

1 Introduction

Hello, I’m , WeChat search Vision" 160a478394ab2a Follow me, focus on front-end technology sharing, a vision is to help the front-end to broaden its horizons to the forefront of the public account within 5 years. Welcome to add me on WeChat ruochuan12 for long-term exchange and learning.

This is the vuex4 source code (the tenth part) learning source code overall architecture series. Learning Source overall architecture series ( What are the must-see JS library ): jQuery , Underscore , lodash , Sentry , vuex , Axios , KOA , Redux , vue-devtools directly open the file function to reveal the secret .

10 source code series articles, small achievements reached , started writing in July 19th, wrote 6 articles in 19 years, 2 articles in 20 years, and 2 articles this year. It's an end. This series should not be updated for a short time. The main reason is that more time and energy are invested, few people see it, and less feedback is received. Then write other articles first. Welcome to continue to follow me ( ).

address of the warehouse of this article is : git clone https://github.com/lxchuan12/vuex4-analysis.git , the best way to read this article, clone the warehouse and debug by yourself, easy to absorb and digest.

If someone talks about how to read the source code, if you are reading the article, you can recommend my source code series articles, that would be really .

My article is written as far as possible so that readers who want to read the source code but don't know how to read it can understand. I always recommend using build the environment breakpoint debugging source code to learn , where will not be where , watch while debugging, rather than just look at . As the goes: 160a478394aced is better to teach people to fish than to teach people to fish .

After reading this article, you will learn:

    1. git subtree Manage sub-repositories
    1. How to learn the source code of Vuex 4 and understand the principle of Vuex
    1. Vuex 4 and differences between Vuex 3
    1. How to use Vuex 4 composition API
    1. Vue.provide / Vue.inject API usage and principle
    1. How to write a Vue3 plug-in
  • and many more

If you are not familiar with Google browser debugging, you can read this article chrome devtools source panel , which is written in great detail. By the way, in the settings I opened, the search code block is supported in the source panel (not supported by default), and a picture is worth a thousand words.
code-folding

Google Chrome is a commonly used tool in our front-end, so we recommend that you learn more. After all, must first sharpen its .

Written before Vuex 3 source article learning vuex source overall architecture, to create their own state management library , if Sichuan blog Vuex source , warehouses have very detailed notes and look at the source code method, so this article will not go into too much Same place as the source code of Vuex 3

1.1 The best way to read this article

Clone my vuex4 source code warehouse git clone https://github.com/lxchuan12/vuex4-analysis.git , by the way, star my vuex4 source code learning warehouse ^_^. Follow the rhythm of the article to debug and sample code debugging, and use chrome to debug the impression more deeply . You don’t need to look closely at the long code of the article, you can look at it carefully when debugging. Reading this kind of source code articles a hundred times may not as good as debugging a few times by yourself, making bold guesses and carefully verifying. Also welcome to add me on WeChat to exchange ruochuan12 .

2. Brief description of Vuex principle

Conclusion First : The Vuex can be disassembled into three key points.
The first point is that each component instance is injected with Store instance of 060a478394afb3.
The second point is that the various methods in the Store instance all serve the attributes in Store
The third point is that the attribute change in Store

This article mainly explains the first point. The second point is in my last article, learning the overall architecture of vuex source code, and creating your own state management library . I will not go into details in this article. The third point is not described in detail in the two articles.

The following is a short code to explain the principle of Vuex

// 简版
class Store{
  constructor(){
    this._state = 'Store 实例';
  }
  dispatch(val){
    this.__state = val;
  }
  commit(){}
  // 省略
}


const store = new Store();
var rootInstance = {
  parent: null,
  provides: {
    store: store,
  },
};
var parentInstance = {
  parent: rootInstance,
  provides: {
    store: store,
  }
};
var childInstance1 = {
  parent: parentInstance,
  provides: {
    store: store,
  }
};
var childInstance2 = {
  parent: parentInstance,
  provides: {
    store: store,
  }
};

store.dispatch('我被修改了');
// store Store {_state: "我被修改了"}

// rootInstance、parentInstance、childInstance1、childInstance2 这些对象中的provides.store都改了。
// 因为共享着同一个store对象。

provide,inject示例图

Read the above official document map, probably know is provide provide parent component Store example, with inject to get to Store instance.

Then, with the question:

1. Why is the attribute in the instance store modified? After the change, the view update will be triggered.

2, Vuex4 as Vue plug-in how to implement and Vue combination.

3. provide and inject , and how to obtain Store in the component instance for each component.

4. Why is there a Store instance object in each component object (the process of rendering the component object).

provide written in the component can be obtained by the sub-component.

3. Vuex 4 major changes

Before looking at the source code, let’s take a look at the Vuex 4 released by release and the major changes mentioned in the official document migration, Vuex 4 release .

from 3.x to 4.0

The focus of Vuex 4 Vuex 4 supports Vue 3 , and directly provides Vuex 3 exactly the same as API , so users can reuse the existing Vuex code Vue 3

Compared to the Vuex 3 version. The major changes are as follows (the others are in the link above):

3.1 Installation process

Vuex 3 is Vue.use(Vuex)

Vuex 4 is app.use(store)

import { createStore } from 'vuex'

export const store = createStore({
  state() {
    return {
      count: 1
    }
  }
})
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'

const app = createApp(App)

app.use(store)

app.mount('#app')

3.2 The core module exports the createLogger function

import { createLogger } from 'vuex'

Next, we will look at these major changes from the perspective of the source code.

4. View the major changes in Vuex 4 from the source code point of view

4.1 chrome debugging Vuex 4 source code preparation

git subtree add --prefix=vuex https://github.com/vuejs/vuex.git 4.0

This way retains the git record information of vuex4 warehouse. For more git subtree use 060a478394b428, please see this article Use Git Subtree to synchronize sub-projects between multiple Git projects in both directions, with a concise user manual .

As a reader friend, you only need to clone my Vuex 4 source code repository https://github.com/lxchuan12/vuex4-analysis.git , and welcome star .

Add vuex/examples/webpack.config.js to devtool: 'source-map' , so that you can turn on the sourcemap debugging source code.

We use the example of the shopping cart in the project to debug, throughout the whole text.

git clone https://github.com/lxchuan12/vuex4-analysis.git
cd vuex
npm i
npm run dev
# 打开 http://localhost:8080/
# 选择 composition  购物车的例子 shopping-cart
# 打开 http://localhost:8080/composition/shopping-cart/
# 按 F12 打开调试工具,source面板 => page => webpack:// => .

It is said that a picture is worth a thousand words. At this time, simply cut a picture for debugging.

vuex debugger

Find the createStore function to hit a breakpoint.

// webpack:///./examples/composition/shopping-cart/store/index.js
import { createStore, createLogger } from 'vuex'
import cart from './modules/cart'
import products from './modules/products'

const debug = process.env.NODE_ENV !== 'production'

export default createStore({
  modules: {
    cart,
    products
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})

Find app.js entrance, in app.use(store) , app.mount('#app') and other marked breakpoint.

// webpack:///./examples/composition/shopping-cart/app.js
import { createApp } from 'vue'
import App from './components/App.vue'
import store from './store'
import { currency } from './currency'

const app = createApp(App)

app.use(store)

app.mount('#app')

Next, we will explain from two aspects: createApp({}) and app.use(Store)

4.2 Vuex.createStore function

Compared to Vuex 3 , new Vuex.Store is actually the same. Just in order to Vue 3 unified with Vuex 4 an additional createStore function.

export function createStore (options) {
  return new Store(options)
}
class Store{
  constructor (options = {}){
    // 省略若干代码...
    this._modules = new ModuleCollection(options)
    const state = this._modules.root.state
    resetStoreState(this, state)
    // 省略若干代码...
  }
}
function resetStoreState (store, state, hot) {
  // 省略若干代码...
  store._state = reactive({
    data: state
  })
  // 省略若干代码...
}

Monitoring data

And Vuex 3 difference is that the data is no longer listening is new Vue() , but Vue 3 provided reactive method.

Vue.reactive function method will not be explained in this article. Because in terms of expansion, you can write a new article again. Just need to know that the main function is to monitor data changes and change the view.

This is the answer to the first question raised at the beginning.

Following the breakpoint, we continue to look at the app.use() method, the plug-in mechanism provided by Vue

4.3 app.use() method

use does is easy to say, adding the passed plug-ins to the plug-in collection to prevent duplication.

Execute the plug-in, if it is an object, install is a function, then pass the parameter app and other parameters to the install function for execution. If it is a function, execute it directly.

// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
function createAppAPI(render, hydrate) {
    return function createApp(rootComponent, rootProps = null) {
      // 代码有删减
      const installedPlugins = new Set();
      const app = (context.app = {
        use(plugin, ...options) {
          // 已经有插件,并且 不是生产环境,报警告。
            if (installedPlugins.has(plugin)) {
                (process.env.NODE_ENV !== 'production') && warn(`Plugin has already been applied to target app.`);
            }
            // 插件的install 是函数,则添加插件,并执行 install 函数
            else if (plugin && isFunction(plugin.install)) {
                installedPlugins.add(plugin);
                // 断点
                plugin.install(app, ...options);
            }
            // 插件本身 是函数,则添加插件,并执行 插件本身函数
            else if (isFunction(plugin)) {
                installedPlugins.add(plugin);
                plugin(app, ...options);
            }
            // 如果都不是报警告
            else if ((process.env.NODE_ENV !== 'production')) {
                warn(`A plugin must either be a function or an object with an "install" ` +
                    `function.`);
            }
            // 支持链式调用
            return app;
        },
        provide(){ 
          // 省略... 后文再讲
        }
      });
    }
}

In the above code, the breakpoint line plugin.install(app, ...options);

Follow the breakpoint to the next step, the install function.

4.4 install function

export class Store{
    // 省略若干代码...
    install (app, injectKey) {
        // 为 composition API 中使用
        //  可以传入 injectKey  如果没传取默认的 storeKey 也就是 store
        app.provide(injectKey || storeKey, this)
        // 为 option API 中使用
        app.config.globalProperties.$store = this
    }
    // 省略若干代码...
}

Vuex4 in install function of the relative ratio Vuex3 a lot simpler in.
The first sentence is for Composition API . Inject into the root instance object.
The second sentence is for option API .

Then break the two sentences, press F11 see the realization app.provide

4.4.1 app.provide

Is simply to context of provides attribute added store = Store instance object .

provide(key, value) {
    // 如果已经有值了警告
    if ((process.env.NODE_ENV !== 'production') && key in context.provides) {
        warn(`App already provides property with key "${String(key)}". ` +
            `It will be overwritten with the new value.`);
    }
    // TypeScript doesn't allow symbols as index type
    // https://github.com/Microsoft/TypeScript/issues/24587
    context.provides[key] = value;
    return app;
}

context from the code above, you can find this code:

const context = createAppContext();

Then we look at the function createAppContext .
context is the context

// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
function createAppContext() {
    return {
        app: null,
        config: {
            isNativeTag: NO,
            performance: false,
            globalProperties: {},
            optionMergeStrategies: {},
            isCustomElement: NO,
            errorHandler: undefined,
            warnHandler: undefined
        },
        mixins: [],
        components: {},
        directives: {},
        provides: Object.create(null)
    };
}

Vue3 document application configuration (app.config)

4.4.2 app.config.globalProperties

app.config.globalProperties official document

usage:

app.config.globalProperties.$store = {}

app.component('child-component', {
  mounted() {
    console.log(this.$store) // '{}'
  }
})

It can also explain why each component can use this.$store.xxx access the methods and properties in vuex

That is to appContext.provides Store instance object is injected into 060a478394b94e. At this time, it is equivalent to the root component instance and config global configuration globalProperties with Store instance object .

So far we have finished reading, createStore(store) , app.use(store) two API .

app.provide is actually used for composition API .

But this is just what the document says. Why is it accessible to every component instance? Let's continue to explore the principle in depth.

Next, let's look at the specific implementation of the source code and why it can be obtained in each component instance.

Prior to this first look at the combined API in how we use Vuex4 , this is a clue.

4.5 How to use Vuex 4 in the composition API

Then we find the following file, useStore is the object of our breakpoint.

// webpack:///./examples/composition/shopping-cart/components/ShoppingCart.vue
import { computed } from 'vue'
import { useStore } from 'vuex'
import { currency } from '../currency'

export default {
  setup () {
    const store = useStore()

    // 我加的这行代码
    window.ShoppingCartStore = store;
    // 省略了若干代码
  }
}

Then press F11 breakpoint, and single-step debugging, you will find that the Vue.inject method is finally used.

4.5.1 Vuex.useStore source code implementation

// vuex/src/injectKey.js
import { inject } from 'vue'

export const storeKey = 'store'

export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

4.5.2 Vue.inject source code implementation

Next, look at the inject function and look at a lot of codes. In fact, the principle is very simple, that is, to find the value provide

If there is no parent, that is, the root instance, vnode.appContext.provides in the instance object is taken.
Otherwise, take the value instance.parent.provides

In the source code of Vuex4 Store instance object.

// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
function inject(key, defaultValue, treatDefaultAsFactory = false) {
    // fallback to `currentRenderingInstance` so that this can be called in
    // a functional component
    // 如果是被一个函数式组件调用则取 currentRenderingInstance
    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 (provides && key in provides) {
            // TS doesn't allow symbol as index type
            return provides[key];
        }
        // 如果参数大于1个 第二个则是默认值 ,第三个参数是 true,并且第二个值是函数则执行函数。
        else if (arguments.length > 1) {
            return treatDefaultAsFactory && isFunction(defaultValue)
                ? defaultValue()
                : defaultValue;
        }
        // 警告没找到
        else if ((process.env.NODE_ENV !== 'production')) {
            warn(`injection "${String(key)}" not found.`);
        }
    }
    // 如果没有当前实例则说明则报警告。
    // 也就是是说inject必须在setup中调用或者在函数式组件中使用
    else if ((process.env.NODE_ENV !== 'production')) {
        warn(`inject() can only be used inside setup() or functional components.`);
    }
}

Then we continue to look inject the corresponding provide .

4.5.3 Vue.provide source code implementation

provide function of the 060a478394bb4b function is actually quite simple, 1. That is, add the key-value pair key/value provides object attribute on the current component instance.

2. Another function is that when the provides of the current component and the parent component are the same, the provides object in the current component instance and the parent will establish a link, which is the prototype [[prototype]] ( __proto__ ).

// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
function provide(key, value) {
    if (!currentInstance) {
        if ((process.env.NODE_ENV !== 'production')) {
            warn(`provide() can only be used inside setup().`);
        }
    }
    else {
        let provides = currentInstance.provides;
        // by default an instance inherits its parent's provides object
        // but when it needs to provide values of its own, it creates its
        // own provides object using parent provides object as prototype.
        // this way in `inject` we can simply look up injections from direct
        // parent and let the prototype chain do the work.
        const parentProvides = currentInstance.parent && currentInstance.parent.provides;
        if (parentProvides === provides) {
            provides = currentInstance.provides = Object.create(parentProvides);
        }
        // TS doesn't allow symbol as index type
        provides[key] = value;
    }
}

provide in the 060a478394bbaf function may not be so easy to understand.

if (parentProvides === provides) {
    provides = currentInstance.provides = Object.create(parentProvides);
}

Let's take an example to digest it.

var currentInstance = { provides: { store: { __state: 'Store实例' }  } };
var provides = currentInstance.provides;
// 这句是我手动加的,在后文中则是创建实例时就是写的同一个对象,当然就会相等了。
var parentProvides = provides;
if(parentProvides === provides){
    provides =  currentInstance.provides = Object.create(parentProvides);
}

After executing this once, currentInstance becomes like this.

{
  provides: {
    // 可以容纳其他属性,比如用户自己写的
    __proto__ : { store: { __state: 'Store实例' }  }
  }
}

In the second execution, currentInstance is:

{
  provides: {
    // 可以容纳其他属性,比如用户自己写的
    __proto__: {
        // 可以容纳其他属性,比如用户自己写的
        __proto__ : { store: { __state: 'Store实例' }  }
    }
  }
}

By analogy, execute provide more times, the longer the prototype chain will be.

In the above inject and provide functions, there is a variable currentInstance current instance, so how did the current instance object come from?

Why each component can be accessed, the idea of dependency injection.
runtime-core.esm-bundler.js is to search for provides in the file 060a478394bc83, then you can search for the createComponentInstance function

Next, how do we create a component instance with the createComponentInstance

4.6 createComponentInstance creates a component instance

You can disable other breakpoints, separate breakpoints here,
For example: const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
Look at the specific implementation.

// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
const emptyAppContext = createAppContext();
let uid$1 = 0;
function createComponentInstance(vnode, parent, suspense) {
    const type = vnode.type;
    const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
    const instance = {
        uid: uid$1++,
        vnode,
        type,
        parent,
        appContext,
        root: null,
        next: null,
        subTree: null,
        // ...
        provides: parent ? parent.provides : Object.create(appContext.provides),
        // ...
    }
    instance.root = parent ? parent.root : instance;
    // ...
    return instance;
}

When you break the point, you will find that vnode has been generated when the root component instance is generated. As for when it was generated, I have compiled a simplified version.

// 把上文中的 appContext 赋值给了 `appContext`
mount(rootContainer, isHydrate) {
    if (!isMounted) {
        const vnode = createVNode(rootComponent, rootProps);
        // store app context on the root VNode.
        // this will be set on the root instance on initial mount.
        vnode.appContext = context;
    }
},

Among them, Object.create is actually to establish a prototype relationship. Put a picture at this time, a picture is worth a thousand words.

直观的图

It is from the column of Teacher Huang Yi Lagou. I wanted to draw a picture by myself, but I think this one is quite good.

4.6.1 The component instance is generated, how to combine them?

At this time, there is also a runtime-core.esm-bundler.js method. In the 060a478394bd87 file, searching for provide( can find the following code:

This code actually looks very complicated. In fact, it mainly provides object or function return value written by the user in the component, and generates an instance object like this:

// 当前组件实例
{
  parent: '父级的实例',
  provides: {
    // 可以容纳其他属性,比如用户自己写的
    __proto__: {
        // 可以容纳其他属性,比如用户自己写的
        __proto__ : { store: { __state: 'Store实例' }  }
    }
  }
}
// webpack:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js
function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) {
  // ...
  if (provideOptions) {
      deferredProvide.push(provideOptions);
  }
  if (!asMixin && deferredProvide.length) {
      deferredProvide.forEach(provideOptions => {
          // 组件中写 provides 可以是对象或者是函数
          const provides = isFunction(provideOptions)
              ? provideOptions.call(publicThis)
              : provideOptions;
          Reflect.ownKeys(provides).forEach(key => {
              provide(key, provides[key]);
          });
      });
  }
  // ...
}

app.provide from top to bottom are injected into each component instance. At the same time, the provides provided by the component itself has also been injected into the instance.

Then we followed the project to verify the statement above. Vue3 at the 060a478394be09 document, you can find that there is a API to get the current component instance.

4.7 getCurrentInstance Get the current instance object

getCurrentInstance supports access to internal component instances for high-level usage or library development.

import { getCurrentInstance } from 'vue'

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance()

    internalInstance.appContext.config.globalProperties // 访问 globalProperties
  }
}

After knowing this API, we can add some code to the code of the shopping cart example. It is easy for us to understand.

// vuex/examples/composition/shopping-cart/components/App.vue
import { getCurrentInstance, provide } from 'vue'
import { useStore } from 'vuex';
setup () {
  const store = useStore()
  provide('ruochuan12', '微信搜索「若川视野」关注我,专注前端技术分享。')

  window.AppStore = store;
  window.AppCurrentInstance = getCurrentInstance();
},
// vuex/examples/composition/shopping-cart/components/ProductList.vue
setup(){
  const store = useStore()

  // 若川加入的调试代码--start
  window.ProductListStore = store;
  window.ProductListCurrentInstance = getCurrentInstance();
  provide('weixin-2', 'ruochuan12');
  provide('weixin-3', 'ruochuan12');
  provide('weixin-4', 'ruochuan12');
  const mp = inject('ruochuan12');
  console.log(mp, '介绍-ProductList'); // 微信搜索「若川视野」关注我,专注前端技术分享。
  // 若川加入的调试代码---end
}
// vuex/examples/composition/shopping-cart/components/ShoppingCart.vue
setup () {
    const store = useStore()

    // 若川加入的调试代码--start
    window.ShoppingCartStore = store;
    window.ShoppingCartCurrentInstance = getCurrentInstance();
    provide('weixin', 'ruochuan12');
    provide('weixin1', 'ruochuan12');
    provide('weixin2', 'ruochuan12');
    const mp = inject('ruochuan12');
    console.log(mp, '介绍-ShoppingList'); // 微信搜索「若川视野」关注我,专注前端技术分享。
    // 若川加入的调试代码--start
}

Output these values in the console

AppCurrentInstance
AppCurrentInstance.provides
ShoppingCartCurrentInstance.parent === AppCurrentInstance // true
ShoppingCartCurrentInstance.provides
ShoppingCartStore === AppStore // true
ProductListStore === AppStore // true
AppStore // store实例对象

控制台输出的结果

Look at the example of the console screenshot output, which is actually similar to the one written above. At this time, if you write and inject a provide('store':'empty string') by store , you must find the 060a478394bef0 written by the user first along the prototype chain. At this time, Vuex cannot be used normally, and an error is reported.

Of course, the injected vuex4 key may not be store , and there is no conflict with the user at this time.

export class Store{
    // 省略若干代码...
    install (app, injectKey) {
        // 为 composition API 中使用
        //  可以传入 injectKey  如果没传取默认的 storeKey 也就是 store
        app.provide(injectKey || storeKey, this)
        // 为 option API 中使用
        app.config.globalProperties.$store = this
    }
    // 省略若干代码...
}
export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

5. Answer the 5 questions raised at the beginning of the next

Unified answer to the 5 questions raised at the beginning:

1. Why is the attribute in the instance store modified? After the change, the view update will be triggered.

A: Use Vue in reactive method for monitoring changes in the data.

class Store{
  constructor (options = {}){
    // 省略若干代码...
    this._modules = new ModuleCollection(options)
    const state = this._modules.root.state
    resetStoreState(this, state)
    // 省略若干代码...
  }
}
function resetStoreState (store, state, hot) {
  // 省略若干代码...
  store._state = reactive({
    data: state
  })
  // 省略若干代码...
}

2, Vuex4 as Vue how and plug Vue combination.

A: app.use(store) be executed when Store in install methods, one is composition API used, provided Store instance of the object instance to the root. One sentence is injected into the global attributes of the root instance and is option API in 060a478394bfd6. They will be injected into each component instance when the component is generated.

export class Store{
    // 省略若干代码...
    install (app, injectKey) {
        // 为 composition API 中使用
        //  可以传入 injectKey  如果没传取默认的 storeKey 也就是 store
        app.provide(injectKey || storeKey, this)
        // 为 option API 中使用
        app.config.globalProperties.$store = this
    }
    // 省略若干代码...
}

3. provide and inject , and how to obtain Store in the component instance for each component.

provide written in the component can be obtained by the sub-component.

Answer: The provide function establishes the prototype chain to distinguish the attributes written by the user of the component instance and the attributes injected by the system. inject function uses the prototype chain to find provides object in the parent instance.

// 有删减
function provide(){
    let provides = currentInstance.provides;
    const parentProvides = currentInstance.parent && currentInstance.parent.provides;
    if (parentProvides === provides) {
        provides = currentInstance.provides = Object.create(parentProvides);
    }
    provides[key] = value;
}
// 有删减
function inject(){
    const provides = instance.parent == null
        ? instance.vnode.appContext && instance.vnode.appContext.provides
        : instance.parent.provides;
    if (provides && key in provides) {
        return provides[key];
    }
}

That is, an example like this:

// 当前组件实例
{
  parent: '父级的实例',
  provides: {
    // 可以容纳其他属性,比如用户自己写的
    __proto__: {
        // 可以容纳其他属性,比如用户自己写的
        __proto__ : { store: { __state: 'Store实例' }  }
    }
  }
}

4. Why is there a Store instance object in each component object (the process of rendering the component object).

Answer: When rendering a component instance, call createComponentInstance and inject it into provides of the component instance.

function createComponentInstance(vnode, parent, suspense) {
    const type = vnode.type;
    const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
    const instance = {
        parent,
        appContext,
        // ...
        provides: parent ? parent.provides : Object.create(appContext.provides),
        // ...
    }
    // ...
    return instance;
}
  1. How do you know so much

Answer: Because someone in the community wrote Vue4 source code article .

6. Summary

This article mainly describes the Vuex4 of Store injecting the 060a478394c1a0 instance into each component, Vuex3 on the change of the installation method of Vuex4 relative to Vuex.createStore , app.use(store) , and in-depth source code analysis Vue.inject , Vue.provide implementation principle.

Vuex4 addition to the installation and use of monitoring data changes in the way the Vue.reactive , and other basic Vuex3.x version makes no difference.

Finally, review the picture at the beginning of the article, which can be said to be the magical effect of the prototype chain.

provide,inject示例图

Do you feel that it is suddenly clear.

Vuex actually Vue a plug-in, knowing the Vuex principle, for himself to Vue write plug-ins also will ease.

If readers find something improper or can be improved, or if there is no clear place, please comment and point out, and welcome to add me to ruochuan12 communicate. In addition, I feel that it is well written, and it is a little helpful to you. You can like, comment, forward and share. It is also a kind of support for me. Thank you very much. If you can pay attention to my front-end public Vision" 160a478394c25d, it would be even better.

on

Hello, I am , WeChat search Vision" 160a478394c2cd Follow me, focus on front-end technology sharing, a vision is to help the front-end to broaden its horizons to the forefront of the public account within 5 years. Welcome to add me on WeChat ruochuan12 for long-term exchange and learning.
There are mainly the following series of articles: learning source code overall architecture series , annual summary , JS basic series

Reference link

Official website document Provide / Inject

github warehouse provide/inject source code

github warehouse provide/inject test

Vuex 4 official Chinese document


若川视野公众号
发布前端技术文章和随笔等。公众号若川视野,公众号经常更新,欢迎关注,长期交流学习。

你好,我是若川。写有 《学习源码整体架构系列》 20余篇。

7k 声望
3.2k 粉丝
0 条评论
推荐阅读
尤雨溪推荐神器 ni ,能替代 npm/yarn/pnpm ?简单好用!源码揭秘!
想学源码,极力推荐之前我写的《学习源码整体架构系列》 包含jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、vue-next-release、vue-this、create-vue等十余...

若川6阅读 6.3k

从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木140阅读 11.9k评论 10

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木60阅读 5.9k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.1k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木39阅读 7k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(>^ω^&lt...

XboxYan41阅读 2.8k评论 14

封面图
还在用 JS 做节流吗?CSS 也可以防止按钮重复点击
举个例子:一个保存按钮,为了避免重复提交或者服务器考虑,往往需要对点击行为做一定的限制,比如只允许每300ms提交一次,这时候我想大部分同学都会到网上直接拷贝一段throttle函数,或者直接引用lodash工具库

XboxYan34阅读 2.2k评论 2

封面图

你好,我是若川。写有 《学习源码整体架构系列》 20余篇。

7k 声望
3.2k 粉丝
宣传栏