Summarize the contents of official documents for your own convenience

introduce

NPM NPM install vuex –save NPM install vuex –save NPM install vuex –save NPM install vuex –save

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

Vue.use(Vuex)
Copy the code

A Store is basically a container that contains most of the states in your application. Vuex differs from pure global objects in the following two aspects: 1. The state storage of VUex is reactive. As the state changes in the store, the component is updated. 2. You cannot directly change the state of the store. Create Store (mutation

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

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
Copy the code

Get the state object using store.state and trigger a state change using the store.mit method

store.commit('increment')
console.log(store.state.count) // -> 1
Copy the code

To access this.$store property from the Vue component, we need to provide the created store for the Vue instance. We need to inject the store mechanism into the root component:

new Vue({
  el: '#app',
  store: store,
})
Copy the code

You can then commit a change from the component’s method:

methods: {
  increment() {
    this.$store.commit('increment')
    console.log(this.$store.state.count)
  }
}
Copy the code

The core concept

State





MapState helper function

When a component needs to fetch multiple states, it can be complicated and redundant to declare all the states as calculated properties. The mapState helper function can be used to help generate calculated properties, which can help us to press the key less

import { mapState } from "vuex"; Computed: {// Mix this object into an external object using the object expansion operator... mapState(["count", "data01"]), }Copy the code
// Use console.log("count", this.count);Copy the code

Getters

VueX allows us to define “getters” (you can think of them as computed properties in the store) in the store. There is a cache and recalculation occurs only when the dependency value changes

The Getter accepts state as its first argument:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})
Copy the code

Getters are exposed as store.getters, and you can access these values as properties:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
Copy the code

Getters can also accept other getters as second arguments:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
Copy the code

Method access allows you to pass parameters to a getter by asking the getter to return a function.

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
Copy the code
store.getters.getTodoById(2) // -> { id: 2, text: '... ', done: false }Copy the code

Note that the getter is called every time it is accessed through a method, without caching the result.

The mapGetters helper function simply maps the getters in the store to local computed properties

import { mapGetters } from 'vuex' export default { // ... Computed: {// Mix getters into a computed object using the object expansion operator... mapGetters([ "doneTodos", "doneTodosCount", // ... ] )}}Copy the code
// Console. log("getter", this.donetodos);Copy the code

If you want to give a getter property another name, use object form:

. MapGetters ({/ / the ` enclosing doneCount ` mapping for ` enclosing $store. The getters. DoneTodosCount ` doneCount: 'doneTodosCount})Copy the code

Mutations

The only way to change the state in Vuex’s store is to commit mutation. Commit mutation is convenient for management, and the states in the state are too scattered and difficult to manage.

Store mutation changes the state

Const store = new Vuex. Store ({state: {count: 1}, mutations: {increment (state) {/ / the status state. Count++}}})Copy the code

Component to call the store.coommit method:

store.commit('increment')
Copy the code

Payload submission

You can pass an additional parameter, payload, to store.mit:

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
Copy the code
store.commit('increment', 10)
Copy the code

In most cases, the payload should be an object, which can contain multiple fields and the mutation recorded will be more readable:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
Copy the code
store.commit('increment', {
  amount: 10
})
Copy the code

Object style submission

Another way to submit mutation is to use an object containing the type attribute directly:

store.commit({
  type: 'increment',
  amount: 10
})
Copy the code
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
Copy the code

The Mutation complies with the Vue response rules

Matters needing attention:

1. It is best to initialize all required properties in your Store in advance. Set (obj,’newProp’,123) or replace the old object with the new object. For example, using the object expansion operator:

state.obj = {... state.obj,newProp:123}Copy the code

3.Mutation must be a synchronization function

Commit Mutation in the component

You can use this. codeStore.mit (‘ XXX ‘) to commit mutation in the component, or use the mapMutations helper function to map methods in the component to a store.mit call (requiring store injection at the root node).

import { mapMutations } from 'vuex' export default { // ... methods: { ... Apply mutations ([' increments ', // map 'this.increment()' to 'this.store.com MIT (' increments ')' 'incrementBy' // Map 'this.incrementBy(amount)' to 'this.incrementBy(amount)'),... Apply mutations ({add: 'increment' // map 'this.add()' to 'this.store.com MIT ('increment')'})}}Copy the code

Mutation are both synchronous transactions handling asynchronous operations see Action

Actions

The Action function takes a context object with the same methods and properties as the Store instance, So you can commit a mutation by calling context.mit, or get state and getters by calling context.state and context.getters. Actions are similar to mutation, except that:

  1. The Action commits mutation rather than a direct state change.
  2. Actions can contain any asynchronous operation

Dispatch Action The Action is triggered by the store.dispatch method

store.dispatch('increment')
Copy the code
// Distribute store.dispath('incrementAsync',{amount: 10}) // distribute store.dispatch({type: 'incrementAsync', amount: 10})Copy the code
Action: {incrementAsync ({commit}) {setTimeout(() => {commit('increment')}, 1000)}}Copy the code

Distribute the Action in the component

Use this.$store.dispatch(‘ XXX ‘) to distribute the action in the component, or use the mapActions helper function to map the component’s methods to the store.dispatch call (which requires injecting store at the root node first) :

import { mapActions } from 'vuex' export default { // ... methods: { ... MapActions (['increment', // Map 'this.increment()' to 'this.$store.dispatch('increment')' // 'mapActions' also supports payloads: 'incrementBy' // map 'this.incrementBy(amount)' to 'this.$store.dispatch('incrementBy', amount)']),... MapActions ({add: 'increment' // map 'this.add()' to 'this.$store.dispatch('increment')'})}}Copy the code

Combination of the Action

Actions are usually asynchronous, so how do you know when an Action ends? More importantly, how can we combine multiple actions to handle more complex asynchronous processes?

First, you need to understand that store.dispatch can handle the Promise returned by the handler of the triggered action, and that store.dispatch still returns promises:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
Copy the code

Now you can:

store.dispatch('actionA').then(() => {
  // ...
})
Copy the code

This is also possible in another action:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}
Copy the code

Finally, if we use async/await (open new window), we can compose actions as follows:

// Suppose getData() and getOtherData() return Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, Commit}) {await dispatch('actionA') // await actionA to complete commit('gotOtherData', await getOtherData())}}Copy the code

A single store.dispatch can trigger multiple action functions in different modules. In this case, the returned Promise will not be executed until all triggering functions have completed.

Module

Because of the use of a single state tree, all the states of an application are grouped into one large object. When the application becomes very complex, the Store object can become quite bloated.

To solve these problems, Vuex allows us to split the Store into modules. Each module has its own state, mutation, action, getter, and even nested submodules — split the same way from top to bottom:

const moduleA = { state: () => ({ ... }), mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: () => ({ ... }), mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: ModuleB}}) Store.state. a // -> moduleA status Store.state. b // -> moduleB statusCopy the code

The project structure