preface

We all know that when using VUE, simple parent-child communication and EventBus can no longer meet our requirements. Too many nested levels and difficult to track changes are two major problems 😡, which can be solved with VUEX. I think everyone has used it before. So today to share with you is a simple implementation of vuex, really super simple, just a few lines of code (there is a link at the end of the article), take you to understand the essence of vuEX, and in the end there will be a few questions (such as time travel, local persistence, etc.) to help you consolidate vuEX.

Front knowledge

Vuex is a vUE based state management tool, or variable sharing in general, you knowthis.$storeThe essence is an object, and if you look at this graph down here, look at itthis.$storeWhat is it (only see the labeled line) πŸ‘‡ :Remember how we used vuex?

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex); // Vue will automatically call the install method of the plug-in
const store = new Vuex.Store({
  state: {... },mutations: {... },actions: {... },getters: {... }})new Vue({
  el: '#app',
  store
})
Copy the code

The four parameters can be divided into two categories, one is to obtain data, the other is to modify data, as shown in the following picture πŸ‘‡ :I think the picture above is pretty good πŸ˜‚, should be pretty clear. The component and store are separate, and the component can obtain data through$store.state ε’Œ $store.gettersComponent to modify data can pass$store.actions ε’Œ $store.mutationsMutations, which also makes it easy to track the changes in the state. In this way, a closed loop is formed, which is also in line with the idea of one-way data flow that we call. There is only one place to change the data, not everywhere, or it will be chaos. The Store is also an example of a singleton pattern, where all components share a global store and each component’s store$storeIt’s the same thing, which makes sense.

In addition, many people can’t remember which is asynchronous and which is synchronous, actions and mutations. Let’s try to remember it this way: “Actions” and “async” both start with “A”, so “actions” is asynchronous, or “actions”, which calls the API, also start with “A”, so “asynchronous” 😳.

Simple implementation

With these concepts in mind, let’s simply implement them in a few lines of code. Start with a simple framework, like this (the website explains how to write a plugin) :

<script src="https://cdn.bootcss.com/vue/2.6.11/vue.js"></script>
<script>
const Vuex = {}
Vuex.install = function (Vue) { // This Vue is provided by Vue
  console.log('Install method starts execution')
}
Vue.use(Vuex)
</script>
Copy the code

Ok, then we write the vuex code in install, now we just need to declare a store object and give the store two properties (state and mutations for example), this I use a very simple code to show you πŸ‘‡ :

 Vuex.install = function (Vue) {
  console.log('Install method starts execution')
  const store = {} // Declare an object
  store.state = new Vue({ // Assign a state attribute to get the value
    data () {
      return {
        msg: 'ha ha'
      }
    }
  })
  store.mutations = { Mutations is given to modify the value
    SETMSG(value) {
      store.state.msg = value
    }
  }
}
Copy the code

Note in the above code that state actually takes advantage of the responsive principle of vue by using new vue () and thus becomes reactive, which is a characteristic of vue. Note that it is not possible to update the view using object.defineProperty, because it is not dependent on vUE, so vuex is strongly dependent on vue. If you have used $set, you can understand why sometimes the data changes and the view does not update the feeling 😬.

πŸ‘Œ, now that we have the store, the next step is to hang it under each component. Here we use the mixin method of Vue.

Vue.mixin({ // This is also fixed: each component performs the following lifecycle
    beforeCreate () {
      this.$store = store // So each component will have this.$store, and each will point to the same store}})Copy the code

Of course, the same can be done with vue.prototype. $store = store. In fact, vue-router can be called in the same way with this. If I’m going to talk about the differences between mixin and Prototype mounts, two things come to mind 😯 :

  • Mixin is on vue instance, prototype is on prototype
  • By mounting the Store on the instance, you don’t have to go down the prototype chain, which gives you a performance boost

I don’t know if you know any other reasons, please leave a comment below.

Ok, so far, we’ve probably written a simple demo, so let’s write an example to test it:

let v1 = new Vue({
  el: '#component1'.computed: {
    data() {
      return this.$store.state.msg
    }
  }
})
let v2 = new Vue({
  el: '#component2'.methods: {
    change() {
      this.$store.mutations.SETMSG(This is the value of mutations that's triggered.)}}})console.log(v1, v2)
Copy the code

Here are the results:Mutations, of course, is what we usually do is we write it through commit, which is essentially a function, mutations is essentially called, and here we simply write commitπŸ‘‡ :

Vuex.install = function (Vue) {... store.commit =function(mutationName, value) { store.mutations[mutationName] && store.mutations[mutationName](value) } ... }...let v2 = new Vue({
  el: '#component2'.methods: {
    change() { // Change the call mode, the result is the same
      Mutations.SETMSG(' This is the value triggered by mutations ')
      this.$store.commit('SETMSG'.This is the value of mutations that's triggered.)}}})Copy the code

The end result is the same, which I won’t show you here. Take a deep breath, so far we’ve achieved a super-simple version of Vuex, here are a few questions to answer πŸ€”.

q&a

Why do you need getters

This is exactly the same thing that we used to write about computed properties, state and getters are like data and computed, so let’s take a look at that.

How do you distinguish between state and commit

We know that vuex only has one channel to change the state, that is, commit, but you can change it without committing, so how do you know that it was changed by committing? “Commit” with “_research”, “commit” with “_research” set to “true”, “_research” to “true”, “research” to change the state of this case. If you change state any other way, it doesn’t change the _research flag, so you can see if you changed it by commit. If you turn on strict mode in VUex, any non-mutation changes will throw an error.

MapState and other auxiliary functions

This class of auxiliary functions is essentially syntactic sugar. Here we take mapState as an example. Let’s review its usage:

import {mapState} from 'vuex'
export default{
    computed: {... mapState(['msg'.'user'])}}Copy the code

Then we can use this. MSG from the page, and actually call this.$store.state. MSG, but it’s easier to write. Let’s see how to do this very easily. Obviously, mapState is a function that takes an array:

function mapState (list) {
  let obj = {}
  list.forEach(stateName= > {
    obj[stateName] = () = > this.$store.state[stateName]
  })
  return obj
}
Copy the code

πŸ‘ Yes, that’s a little bit of code, and the same goes for the other map helper functions.

Local persistence

  • We can save the state to localStorage or sessionStorage for each commit, and then read the state value from the localStorage first during page initialization, but be aware of the frequent storage problems.
  • We can use the beforeUnload event to save the state value before the page is unloaded, which is very efficient.

Shuttle time

This is a feature of the devtoolPlugin, because all state changes are recorded during development. The “time travel” feature allows us to go back or back to a certain state, essentially replacing the current state with one of the recorded states. Let’s take a look at the Vuex Store to provide us with such a function replaceState (really direct replacement πŸ˜‚), the specific code is πŸ‘‡ :

replaceState (state) {
    this._withCommit(() = > { // This is the _commiting flag
      this._vm.state = state
    })
  }
Copy the code

Here are two small screenshots to help you understand:

summary

If you have to say the most core point of VUex, it is the use of vue response, I think this is the most important. Finally, I hope this article can be helpful to you. I do not know whether it is clear to write 😁. I wish you all the best not to invade and work happily.

Ps: the simplest version of VUEX code address, hardcover version of VUEX code address