Vuex principles, to be able to build wheels to measure the learning effect

Source code link

Github.com/kkxiaojun/k…

background

Unified data state management using VUEX has been available for some time. But other than looking at document pasting and copying apis, I didn’t seem to get much out of it.

For some things to know more about:

How are actions implemented

What about mutations

How is getters implemented

.

So, hurry up, learn to learn, output some handwritten vuEX core code process.

Vuex core API practices

After all, Vuex is a plug-in for VUE.

Refer to vue’s plug-in mechanism

Cn.vuejs.org/v2/guide/pl…

Use (Vuex), which is the mechanism by which Vue installs plug-ins, requires Vuex to expose an install method that passes Vue to install

Without further ado, let’s begin…

Project preparation

Create a basic project with VUe-CLI

The demo, making portal

Github.com/kkxiaojun/k…

1. Vue plug-in implementation

The Vue plug-in exposes the install method. And mount $store on vue. prototype. Then export the install and Store instances

class Store {
  constructor() {
    this.name = 'dajun'}}function install(Vue) {
  Vue.prototype.$store = new Store()
}
export default { Store, install }
Copy the code

main.js

import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false

console.log('store===>', store)

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

Copy the code

App.vue

  created() {
    console.log('this.$store'.this.$store)
  },
Copy the code

2. Implementation of Store

import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false

console.log('store===>', store)

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

Copy the code

Looking at main.js,store is passed in via new Vue

How can each component get an instance of $Store?

We need to mount it using mixin on the beforeCreate so that we can get the store passed in via this.$option.

Then distinguish between root and child components

// Vue plugin mechanism
function install (vue) {
  Vue = vue
  Vue.mixin({
    beforeCreate() {
      // The root component has store
      if (this.$options && this.$options.store) {
        this.$store = this.$options.store
      } else {
        / / child component
        this.$store = this.$parent && this.$parent.$store
      }
    }
  })
}
Copy the code

Here are a few questions:

  1. Mixins are used to mix the contents of mixins into the initial parameters of Vue$options;
  2. Why is itbeforeCreate? This part, to understand the initialization of the life cycle,createdWhen,$optionIt’s already initialized.

$store.state. Xx = “” $store.state. Xx = “” $store.state. Is that ok? In fact, this assignment is fine, and state is still reactive. So why commit?

  1. Vuex can record every state change, save state snapshots, and implement operations such as time roaming and rollback.

About global variables

  1. There’s no record, and two, it’s hard to find

3. state

Single data rendering: simple parameter transfer

class Store {
  constructor(options = {}) {
    this.state = options.state
  }
}
Copy the code
import Vue from 'vue'
import Vuex from './myVuex'

Vue.use(Vuex)

const vuexObj = new Vuex.Store({
  state: {
    num: 0}})export default vuexObj
Copy the code

Print kan kan, no problem

Considering that state should be reactive, then…

4. The response type

An easy way to do this is to use the reactive form of Vue, new Vue() and pass in reactive data

let Vue
class Store {
  constructor(options = {}) {
    this.vm = new Vue({
      data: {state: options.state
      }
    })
  }
}

// Vue plugin mechanism
let install = function (vue) {
  Vue = vue
  vue.mixin({
    beforeCreate() {
      // The root component has store
      if (this.$options && this.$options.store) {
        vue.prototype.$store = this.$options.store
      } else {
        / / child component
        vue.prototype.$store = this.$parent && this.$parent.$store
      }
    }
  })
}

export default {
  Store,
  install
}
Copy the code

5. getter

You can use Object.defineProperty to proxy a getter, get the value of the getter, and perform the function calculation. Finally, mount to $store.getters

defineGetters(options) {
  this.getters = {}
  let getters = options.getters || {}
  Object.keys(getters).forEach(key= >{
      Object.defineProperty(this.getters, key, {
          get:() = >{
            console.log('this.state'.this.state)
            return getters[key](this.state)
          }
      })
  })
}
Copy the code
const vuexObj = new Vuex.Store({
  state: {
    num: 0
  },
  getters: {
    getNum(state) {
      return state.num
    }
  },
})
Copy the code

6. mutation

Just look at the use of mutaion in VUex. You only need to record the function and update the data at commit time

class Store {
  constructor(options = {}) {
    // Add responsiveness
    this.vm = new Vue({
      data: {state: options.state
      }
    })
    // mutations
    this.defineMutations(options)
  }
  defineMutations(options) {
    this.mutations = {}
    let mutations = options.mutations || {}
    Object.keys(mutations).forEach(mutationName= >{
        this.mutations[mutationName] = (arg) = > {
          mutations[mutationName](this.state, arg)
        }
    })
  }
  commit = (method, arg) = > {
    console.log(`commit:mutations:${method}= = = > `, method)
    this.mutations[method](arg)
  }
  // To access state directly
  get state() {
    return this.vm.state
  }
}
Copy the code

7. action

Action, which is similar to mutation

class Store {
  constructor(options = {}) {
    // Add responsiveness
    this.vm = new Vue({
      data: {state: options.state
      }
    })
    // actions
    this.defineActions(options)
  }
  defineActions(opotions) {
    this.actions = {}
    let actions = opotions.actions
    Object.keys(actions).forEach(actionName= > {
      this.actions[actionName] =(arg) = > {
        // Arrow function, not bound to this. Here this is an instance of $store
        actions[actionName](this, arg)
      }
    })
  }
  dispatch(method, arg) {
    console.log(  `dispatch:actions:${method}= = = > `, method)
    this.actions[method](arg)
  }
  commit = (method, arg) = > {
    console.log(`commit:mutations:${method}= = = > `, method)
    this.mutations[method](arg)
  }
  // To access state directly
  get state() {
    return this.vm.state
  }
}
Copy the code

Note that {commit} is the deconstruction of this, store instances

The final result

At first glance, it is a bit shabby (even a small wheel is a wheel?).

Of course, there are mapState mapMutations, the realization of the modules. Interested, you can practice it yourself

The demo link

Finally, the demo link is attached

Github.com/kkxiaojun/k…