MEMEPh. ideas that are worth sharing...

Learn Vuex from scratch

I. Introduction


When our application encounters multiple components sharing state, it will require multiple components to depend on the same state or behaviors from different views need to change the same state. Previous workaround:

a. Define the data and the behavior of operating the data in the parent component;

b. Pass the data and the behavior of manipulating the data to the various sub-components required (multi-level transmission may be required)

The method of passing parameters will be very cumbersome for multi-level nested components, and cannot do anything for state transfer between sibling components. When building the following pages, you may experience a breakdown in the communication between vue components, especially the communication between non-parent and child components. At this point, vuex should be used to easily solve the communication problem between components.

 

2. What is Vuex


Vuex is a state management pattern developed for Vue.js applications. It uses a centralized store to manage the state of all components of the application, and uses corresponding rules to ensure that the state changes in a predictable manner. The key here is centralized storage management. Simply put, centralized management (read/write) of the shared state of multiple components in a vue application .

 

3. What is the principle of Vuex


1. Briefly introduce the principle of Vuex

Vuex implements a one-way data flow, and has a State to store data globally. When a component wants to change the data in the State, it must be done through Mutation. Mutation also provides a subscriber mode for external plug-ins to call to obtain the update of State data. When all asynchronous operations (common in calling the back-end interface to asynchronously obtain updated data) or batch synchronous operations need to go through Action, but Action cannot directly modify the State, it is still necessary to modify the data of the State through Mutation. Finally, according to the change of State, it is rendered to the view.

2. Briefly introduce the main functions of each module in the process:

 

4. When to use Vuex

While Vuex helps us manage shared state, it also comes with more concepts and frameworks. This requires a trade-off between short-term and long-term benefits.
If your application is simple enough, you'd better not use Vuex, because using Vuex can be tedious and redundant. A simple  global event bus  is enough for what you need. However, if you need to build a medium-to-large single-page application, you will likely be thinking about how to better manage state outside of components, and Vuex will be the natural choice.

 

5. Vuex installation (limited development environment to vue-cli)

First, you need to install the vue-cli scaffolding. For mainland users, it is recommended to set the npm registry source to a domestic mirror (Taobao mirror), which can greatly improve the installation speed.

npm config set registry https://[registry.npm.taobao.org](http://registry.npm.taobao.org/)
npm config get registry//After configuration, you can verify the success in the following ways
npm install -g npm --registry=[https://registry](https://registry/).npm.taobao.org
//npm install scaffolding
npm install -g vue-cli
vue init webpack my-vue
cd my-vue
npm install
npm run dev


After the scaffolding is installed, install vuex

npm install vuex --save

 

6. How to use Vuex


1. How to achieve the following effects through Vue?

This small demo is easy to implement with Vue. The core code is as follows:

<div class="hello">
<p>click {{count}} times,count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
 
export default {
name: "HelloWorld",
data() {
return {
count: 0
};
},
computed: {
evenOrOdd() {
return this.count % 2 === 0 ? "even" : "odd";
} 
},
methods: {
increment() {
this.count = this.count + 1;
},
decrement() {
this.count = this.count - 1;
},
// add 1 only for odd numbers
incrementIfOdd() {
if (this.count % 2 === 1) {
this.count = this.count + 1;
} 
},
// add 1 after two seconds
incrementAsync() {
setInterval(() => {
this.count = this.count + 1;
} }, 2000);
} 
} 
}

 

2. How to transform the above code through Vuex?


① Create a store.js file

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {// Contains multiple objects that directly update the state function
INCREMENT(state) {
state.count = state.count + 1;
} },
DECREMENT(state) {
state.count = state.count - 1;
} 
},
getters: { // Automatically call and return the property value when the property value is read
evenOrOdd(state) {
return state.count % 2 === 0 ? "even" : "odd";
} }
},
actions: { // Objects containing multiple corresponding event callback functions
incrementIfOdd({ commit, state }) { // conditional action
if (state.count % 2 === 1) {
commit('INCREMENT')
} 
} },
incrementAsync({ commit }) { //Asynchronous action
setInterval(() => {
commit('INCREMENT')
} }, 2000);
} 

} 
})
export default store //Encapsulate the code with export default so that it can be referenced externally


② Introduce the store.js file into the main.js file

import store from './store'
new Vue({
el: '#app',
router,
store,//register the store on vuex: all component objects have one more attribute $store
components: { App },
template: '<App/>'
})


③ Create a new template HelloWorld.vue

<template>
<div class="hello">
<p>click {{count}} times,count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
computed: {
count() {
return this.$store.state.count;
},
evenOrOdd() {
return this.$store.getters.evenOrOdd;
} 
},
methods: {
increment() {
this.$store.commit("INCREMENT");
},
decrement() {
this.$store.commit("DECREMENT");
},
// add 1 only for odd numbers
incrementIfOdd() {
This.$store.dispatch("incrementIfOdd"); //Trigger the corresponding action call in the store
},
// add 1 after two seconds
incrementAsync() {
this.$store.dispatch("incrementAsync");
} 
} 
};
</script>

Since the state in the store is responsive, when a Vue component reads the state from the store, if the state in the store changes, the corresponding component will be updated efficiently accordingly. Calling the state in the store in a component is as simple as returning it in a computed property. The only way to change the state in the store is to explicitly commit mutations.

 

3. How to optimize the above code through auxiliary functions such as mapState?

import { mapActions, mapGetters, mapState, mapMutations } from "vuex";
...
 computed: {
    ...mapState(["count"]),
    ...mapGetters(["evenOrOdd"])
    }
  methods: {
    ...mapActions(["incrementIfOdd", "incrementAsync"]),
    ...mapMutations(["increment", "decrement"])
    }

It must be noted that the increment function name in the HelloWorld.vue file must be consistent with the mutation in the store.js file before it can be written as...mapMutations(["increment", "decrement"]), for the same reason, incrementIfOdd and incrementAsync are also To be consistent with store.js file actions.

 

7. the use of Vuex attention points


1. How to pass parameters in Mutations

First add a parameter n to the add method in the store.js file

  mutations: {
    INCREMENT(state,n) {
      state.count+=n;
    },
    DECREMENT(state){
        state.count--;
    }
  }


Then modify the parameters passed by the button's commit() method in HelloWorld.vue

 increment() {
      return this.$store.commit("INCREMENT",2);
    },
 decrement() {
      return this.$store.commit("DECREMENT");
    }

 

2. How to understand getters

Getters means to obtain from the surface, which can be regarded as a kind of re-editing before the data is obtained, which is equivalent to a filtering and processing of the data . Getters are like computed properties, the return value of a getter is cached according to its dependencies and only recalculated when its dependencies change.

For example: to operate on the count in the store.js file, add 100 to it before outputting it.

First, introduce getters in Vuex.Store() in store.js

getters:{
     count:state=>state.count+=100
  }

Then configure the computed in HelloWorld.vue. There can only be one computed property in the vue constructor. If you write more than one, only the last computed property is available, so use the spread operator "..." to write the previous section. The computed property does a makeover.

 computed: {
   ...mapGetters(["count"])
}


3. The difference between actions and mutations

Actions are basically the same as the above Mutations, the difference is that actions change the state asynchronously, while Mutations change the state synchronously .

The meaning of synchronization is that each mutation can correspond to a new state after the execution is completed (same as reducer), so that devtools can take a snapshot and save it, and then it can be time-traveled at will. If you open the devtool to call an asynchronous action, you can clearly see when the mutation it calls was recorded, and you can immediately check their corresponding status.