Recently, the principle of VUEX has been reviewed systematically and a mini-vuex has been realized by hand.

Building infrastructure

  • To achieve the Store class
  • Implementing the install method
let Vue
class Store{
    constructor(){}}function install(_vue) {
    Vue = _vue
}

export default { Store, install }
Copy the code

Since an instance of Vuex is done via new vuex.store (), the export structure is {Store, install}.

Registered $store

Call the applyMixin () method for each component and inject this.$store into the beforeCreate life cycle for each component.

function install(_vue) {
    Vue = _vue
    Vue.mixin({
        beforeCreate() {
            // The root component will be stored in store
            if(this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}
Copy the code

Make state responsive data

The state of Vuex is reactive, and vUE’s data is reactive. The state is stored in the data of vUE instance components

class Store{
    constructor(options) {
        this._vm = new Vue({
            data() {
                return {
                    $$state: options.state
                }
            }
        })
    }
    get state() {
        return this._vm._data.$$state
    }
    set state(v) {
        console.error('State cannot be changed directly')}}Copy the code

Proxy responsive data is processed in new Vue and state is hidden from the user to modify state directly

To realize the commit

Save ations and mutations first

Commit to achieve

The commit(type, payload) parameter 1 is the name of the mutations function, which is obtained based on type and executed

Our COMMIT operation essentially changes the data value of this component

Realize the dispatch

Let’s take a look at the call arguments to functions in actions

actions:{
    add({ commit, dispatch, state }, payload){}}Copy the code

So we can see that the first argument to an Actions function is actually a Store instance

Bind this in the constructor constructor

conclusion

It can be seen that its implementation completely uses the responsive design of VUE itself, and the dependency listening and collection belong to the proxy hijacking of the object Property set GET method by VUE. The store in Vuex is essentially a hidden Vue component without a template


We need to bind this to commit and dispatch, because if we do not bind this, this will be undefined.

Why is this equal to undefined

We bind this to the constructor function because this is undefined if we do not bind this to the commit call, so why should this equal undefined?

So let’s go back

‘Runtime’ is also an object, and this refers to the object where the runtime is located.

  • If a function runs in the global environment, this points to the top-level object (the Window object in browsers).
  • If a function is run as a method on an object, this refers to that object.
  • If a function is a constructor, this refers to its instance object.

The this object inside the arrow function is the object at which it was defined, not the object at which it was used.

Normally this will end up pointing to the window, so why undefined?

This is because of strict mode **”use strict”**, in which no global variables can be accidentally created, so this is not undefined for window

Note:

In the arrow function, this points to the object on which the runtime is located, and use strict is moved inside the function, so this is the global variable window.

const useName = () = > {
    "use strict";
    console.log(this)}; useName();//Window
Copy the code

The complete code

let Vue
class Store{
    constructor(options) {
        this._mutations = options.mutations
        this._actions = options.actions
        this._vm = new Vue({
            data() {
                return {
                    $$state: options.state
                }
            }
        })
        this.commit = this.commit.bind(this)
        this.dispatch = this.dispatch.bind(this)}get state() {
        return this._vm._data.$$state
    }
    set state(v) {
        console.error('State cannot be changed directly')}commit(type, payload) {
        const mutation = this._mutations[type]
        if(! mutation) {console.error('no mutation exists')
            return
        }
        mutation(this.state, payload)
    }
    dispatch(type, payload) {
        const action = this._actions[type]
        if(! action) {console.error('Non-existent Action')
            return
        }
        return action(this, payload)
    }
}

function install(_vue) {
    Vue = _vue
    Vue.mixin({
        beforeCreate() {
            // The root component will be stored in store
            if(this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}

export default { Store, install }
Copy the code