Official explanation: Vuex is a state management mode developed specifically for vue.js applications.

  • It uses centralized storage to manage the state of all components of an application and rules to ensure that the state changes in a predictable way.

  • Vuex is also integrated into Vue’s official debugging tool devTools-Extension

    What exactly is state management? : Simply think of it as storing variables shared by multiple components in an object

But what state do we need to share across multiple components?

  • User login status, user name, profile picture, location information and so on.
  • A collection of goods, items in a shopping cart, etc
  • This state information can be stored and managed in a unified place, and it’s responsive.

State management of a single component

It is very simple to manage the state of a single component. Vue already helps us manage the state of a single component, where state is an attribute in data.

Multi-component state management

In multi-component state management, multiple views depend on the same state (when a state changes, multiple interfaces need to be updated), and Actions of different interfaces need to modify the same state. However, we only need to access and modify the same state according to vuex’s operation specifications. This is the basic idea behind Vuex.

In the figure, Vue Components represents the page, dotted boxes contain Vuex processing logic, Backend API represents asynchronous network requests, and Devtools represents the status tracking tool.

Talk is cheap, show me the code.


Install the Vuex plug-in

The plug-in configuration

  1. Download the Vuex plug-in
npm install vuex --save
Copy the code
  1. Create a store directory in the SRC directory and create the index.js file in that directory
  2. Write the index.js file, which is often used to assemble files when dividing multiple modules.
import Vue from 'vue'
import Vuex from 'vuex'

// Install the plug-in
Vue.use(Vuex)

// Create an object
const store = new Vuex.Store({  // The first letter of the Store must be uppercase, otherwise an error will be reported
  state: {},mutations: {},getters: {},actions: {},modules:{}
})

// Export objects
export default store
Copy the code
  1. Write the main.js file
import Vue from 'vue'
import App from './App'
import store from './store'

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

Copy the code

So we can get the store object as this.$store.

How do I change the value of state in VUEX

// state
state: {counter:100
}

// Define two methods for modifying counter in mutations
mutations: {increment(state){
    state.counter++
  },
  decrement(state){
    state.counter--
  }
}

// display in the component
<div id='app'>
		{{$store.state.counter}}
		<button @click="addtion"> since the add/button ><button @click="subtraction">Since the reduction/button >. < / div > the methods: {addtion(){
    this.$store.commit('increment') // Commit to increment method in mutation
  },
  subtraction(){
    this.$store.commit('decrement') // Commit to the Decrement method in mutation}}Copy the code

Ok, that’s the easiest way to use Vuex.

Let’s make a simple summary of the steps:

  • Extract a common Store object that holds state shared across multiple components
  • Placing the Store object in a new Vue ensures that it can be used in all components
  • Access the state saved in the Store object in other components
    • State is accessed via the this.$store.state property
    • Use **this. codestore.com MIT (‘ methods in mutations ‘)** to change the state

Matters needing attention:

  • We submitted mutations instead of directly changing this.$store.state.counter
  • This is because Vuex can track state changes more explicitly, so don’t change this.$store.state.counter directly

Getters a thing or two

Getters properties

The getters property is similar to the calculation property, simplifying expression writing

// state
state: {students:[
    {id:0.name:'yang'.age:25},
    {id:1.name:'cai'.age:18},
    {id:2.name:'zheng'.age:20},
    {id:3.name:'jiong'.age:10}}]/ / define getters
getters: {more19stu(state){
    return state.students.filter(s= >s.age > 19)}}/ / use getters
{{$store.getters.more19stu}}
Copy the code

Getter property as argument

getters:{
  more20stu:state= > {
    return state.students.filter(s= > s.age >= 20)},more20stucount:(state,getters) = > {		// The second argument is getters
    return getters.more20stu.length
  }
}
Copy the code

Now we have a new requirement, the age is uncertain, that is, it is not a fixed value of 20, how can we solve it?

MoreAgeStuCount returns elements older than age

{{$store.getters.moreAgeStuCount(20)}}
Copy the code
// The core code makes the getters moreAgeStuCount property a closure function with access to state
moreAgeStuCount: state= > {
			return function(age){
				return state.students.filter(s= > s.age > age)
			}
}
Copy the code

Mutation is created to modify State

There is only one way to update the status of Vuex’s store: commit Mutation

Mutations create an If not, create If you want to change the data in state but don’t have the corresponding function

Mutation mainly includes two parts:

  • Event type (type, string)
  • A callback function (handler) whose first argument is state
// mutation definition
mutations: {increment(state){
    state.count++
  }
}
// Update with mutation
addtion:function(){
  this.$store.commit('increment')}Copy the code

Common commit: When updating data via mutation, we sometimes want to carry additional parameters

  • The additional parameter is called the Payload of mutation.
// index.js file
decrement(state,payload){
  state.count -= payload
}
/ / componentsSubstraction:function(){
  this.$store.commit("decrement".2)		// Only one argument is passed
}
Copy the code

But what if there is more than one parameter?

  • For example, we have a lot of parameters to pass
  • And when you do that, you usually pass it around as an object, payload, which is an object
  • And extract the relevant information from the object
// index.js file
mutations: {changecount(state,payload){
    state.count = payload.count
  	}
}

/ / componentsAltcount:function(){
  this.$store.commit("changecount", {count:0})}Copy the code

It is important to note that the above commit via COMMIT is a common method

this.$store.commit('increment')
this.$store.commit("decrement".2)
this.$store.commit("changecount", {count:0})...Copy the code

Vue also provides another style, which is an object containing the Type attribute

// index.js file
mutations: {changecount(state,payload){
    state.counter += payload.count
  }
}

// Payload is printed as follows
{
  count: 5
	type: "decrement"
}


/ / components
let count = 5
this.$store.commit({			// Pass only one object argument containing the type attribute
  type:'changecount',
  count
})
Copy the code

Mutation also provides a way to use constant types. The types are recorded as uniform constants in a file for easy use by other components.

/ / mutation - types. Js file
export const INCREMENT = 'increment'	Since the increase / / counter

// use the action.js file
import {INCREMENT} from './mutation-types.js'
export default {
  actAddcount({commit},num){
    commit({
      type:'INCREMENT',
      num
    })
  }
}

// mutation. Js file is used
import {INCREMENT} from './mutation-types.js'
export default {
  [INCREMENT](state,payload){
    state.counter +=  payload.num
  }
}
Copy the code

Actions Asynchronous operations

Vuex required that the methods in Mutation should be synchronous methods, and asynchronous operations should not be carried out in Mutation. The main reason was that devTools could help us capture the snapshot of Mutation when we used DevTools. In case of asynchronous operation, Devtools will not be able to keep track of when an operation is being completed to allow data inconsistencies to occur.

If changing State is simultaneous, you can skip actions and submit Mutations directly

However, in some cases, we do want to perform asynchronous operations in Vuex, such as network requests, where action is used instead of mutation to perform asynchronous operations.

// The use of action
actions: {// context context, and the first argument to the mutation and getter functions is state
  actUpdateInfo(context){}}// Trigger events in the component
cpnUpdateInfo(){
  this.$store.dispatch('actUpdateInfo').then(res= >{console.log(res)}) // Print "Successfully modified status"
}
Copy the code

If an asynchronous function wants to tell the component when it has finished executing, use the ES6 Promise approach

actions:{
  // The first argument is context, and the first argument to the mutation and getter functions is state
  actUpdateInfo(context){
    return new Promise((resolve,reject) = >{	
      // Implemented internally within VUex, the returned Promise object will be assigned to the result of the component on the page after dispatch
      setTimeout(() = >{		// Use asynchronous code in actions functions
        context.commit('updateInfo')	// Still cannot skip mutation to change state
        resolve('Changed status successfully')},1000)}}}cpnUpdateInfo(){
  this.$store.dispatch('actUpdateInfo').then(res= >console.log(res))
}
Copy the code

MapState, mapGetters, mapActions, mapMutations

// Components use mapGetters, mapState, mapActions, mapMutations
<script>
  import {mapGetters,mapState,mapActions,mapMutations} from 'vuex'
	export default {
    name:'... ', the methods: {The ES6 syntax uses the object expansion operator to blend this object into external objects. mapActions(['actUpdateInfo']),
        ...mapMutations(['increment'])
			/* This. actUpdateInfo will map to this.$store.dispatch('actUpdateInfo') this.increment will map to this.$store.dispatch('actUpdateInfo') */
    }
    computed: {... mapState(['counter']),
      / *... MapState ({cc:'counter' // take an alias,mapGetters, mapActions, mapMutations, and this.cc will map to this.$store.state.counter}) */. mapGetters(['more20stu'.'moreAgeStuCount']), // Access is the same as state variables
      test(){... } } } </script>Copy the code

Modules Modular cutting

Module means module. Why do we use modules in Vuex? Vue uses centralized state management, meaning that a single data source means that a lot of state is managed by Vuex. When the application becomes very complex, the Store object can become quite bloated. Vuex allows us to split the store into modules. Each module has its own state, mutations, actions, getters, and even nested submodules — split the same way from top to bottom.

Vuex configuration file information


import Vue from 'vue'
import Vuex from 'vuex'

// Install the plug-in
Vue.use(Vuex)

const moduleA = {
	namespaced:true.// Namespace key attributes
  state: {module:'moduleA'.// The state attribute in module A and module B can be the same
		name:'Joe'.num:20
	},
  getters: {Aget1(state){
			return "Hello, I am"+state.name+"This year I"+state.num+"Age"		// Access the local state
		},
		Aget2(state,getters){
			return "Let me introduce myself." + getters.Aget1
		},
		Aget3(state,getters,rootState){
			return "This is my chief steward." + rootState.name + "This year there are." + rootState.num + "Age"
		},
		Aget4(state,getters,rootState,rootGetters){
			return rootGetters.say
		}
	},
  mutations: {add(state,payload,a){
			state.num += payload.number
		}
	},
  actions: {actadd({commit},payload){
			commit('add',payload)
		}
	}
}
const moduleB = {
	namespaced:true.// Namespace key attributes
  state: {module:'moduleB'.// The state attribute in module A and module B can be the same
		name:'bill'.num:100
	},
  getters: {Bget1(state){
			return "Hi I'm"+state.name+"This year I"+state.num+"Age"}},mutations: {add(state,payload){
			state.num += payload.num
		}
	},
  actions:{}
}

// Create an object
const store = new Vuex.Store({
	state: {
		name:'囧 Handsome'.counter: 100.num:1000
	},
	mutations: {
		increment(state) {
			state.counter++
		},
		decrement(state,payload){},updateInfo(state){
			state.counter -= 5}},getters: {
		say(state){
			return "Welcome to Beijing"}},actions: {// The first argument is context, and the first argument to the mutation and getter functions is state
	  actUpdateInfo(context,msg){			Commit (...) {commit (...);
			console.log(msg);
	    return new Promise((resolve,reject) = >{	
	// Implemented internally within VUex, the returned Promise object will give the page component the result after dispatch, telling the App component that the modification was successful, so that the app component can take the next action
	      setTimeout(() = >{					// Use asynchronous code in actions functions
	        context.commit('updateInfo')    // Still cannot skip mutation to change state
	        resolve('success')},1000)})}},modules: {
		a:moduleA,		// Access the module's state through this.$store.state.a
		b:moduleB		// Access the module's state through this.$store.state.b}})// Export objects
export default store
Copy the code

Access method after module partition

/ / app components<template> <div id='app'> "Anum :"{{Anum}} <br> "Bnum :"{{Bnum}} <br> "Gnum :"{{Gnum}} <br> <button @ click = "test" > program test button < / button > < / div > < / template > < script > import {mapState mapMutations, mapGetters, mapActions} the from 'vuex' export default { name: 'app', methods:{ ... mapMutations('a',['add']), ... mapActions('a',['actadd']), Test (){this. codestore.com MIT ('add',{number:5}) // Call add this. codestore.com MIT ('a/add',{number:5}) from mutations in the main module only Mutations add this. codestore.com MIT ('b/add',{number:5}) {name:state => state.a.name, // alias Anum:state => state.a.name, Bnum:state => state.b.name, Gnum:state => state.num }), ... mapGetters('a',['Aget1','Aget2','Aget3','Aget4']), ... MapGetters (' b ', {B1: 'Bget1' / / alias})}} < / script >Copy the code

Additional: view the printed information of each parameter in getters:

  1. State Print result

  1. Getters prints the result

  1. RootState Prints the result

  1. RootGetters Prints the result