What is Vuex?
Vuex is a state management pattern developed specifically for Vue.js applications. It uses a centralized storage to manage the state of all components of the application, and uses corresponding rules to ensure that the state changes in a predictable manner.
Why do you need Vuex?
In Vue.js applications, data passing and state management between components can become very complex, especially in large applications. In these cases, Vuex can be a powerful tool to simplify state management.
Vuex can make the data flow of the application clearer and easier to maintain, and it can also make it easier to track the data flow.
Core idea
State
state in Vuex represents all state in the application. It can be seen as a single source, the only source of data. The state in Vuex is reactive, when it changes, all components that depend on it will re-render.
Define a state:
const store = new Vuex.Store({ state: { count: 0 } })
Read state in component:
// read count state from store computed: { count () { return this.$store.state.count } }
Getter
Getter is a computed property in Vuex, used to derive some new state from state. Getters can accept other Getters as parameters, allowing us to define a Getter inside another Getter.
Define a getter:
const store = new Vuex.Store({ state: { todos: [ { id: 1, text: 'study Vue.js', done: true }, { id: 2, text: 'study Vuex', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } })
Read the getter in the component:
// Read the doneTodos getter from the store computed: { doneTodos () { return this.$store.getters.doneTodos } }
Mutation
Mutation: is the only recommended way to change state in Vuex, it is similar to events, each mutation has an event type of type string and a callback function, which is where the actual state change is made. In mutation, we can directly change the state, and Vuex will track the state changes, so that these changes can be used in Vue components. It should be noted that mutation must be a synchronous function.
Define a mutation:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++ } } }) // used in the component this.$store.commit('increment')
In the above code, we created a Vuex store and defined a state object to store the application state. At the same time we also define a mutations object to store the methods used to change the state. In the mutations object, we define a method called increment, which is used to increment the count property in the state by 1. In a component, we can use the $store.commit method to commit a mutation, which triggers a state update.
It should be noted that mutation s must be synchronous functions because they are used to change the state, if we use asynchronous functions, then the order and consistency of state updates cannot be guaranteed.
Action
Action s are similar to Mutation s, but can operate asynchronously. The Action's callback function accepts a context parameter, which has the same methods and properties as the store instance, so we can use context.commit() to trigger Mutation, and access state and Getter s through context.state and context.getters.
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++ } }, actions: { incrementAsync({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } }) // used in the component this.$store.dispatch('incrementAsync')
In the above code, we create an action called incrementAsync, and receive the commmit in the context as a parameter. What it does is delay for 1 second, and then call the commit method to trigger the increment mutation to update the state. In components, we can use the $store.dispatch method to trigger an action to change the state asynchronously.
Note that an action can return a Promise, allowing the caller to wait for the asynchronous operation to complete. This allows us to perform some additional operations after the asynchronous operation completes.
Module
Module is an organizational method in Vuex that allows the store to be split into multiple modules. Each Module has its own state, getter s, mutation s, action s.
const moduleA = { state: { countA: 0 }, mutations: { incrementA(state) { state.countA++ } }, actions: { incrementAAsync({ commit }) { setTimeout(() => { commit('incrementA') }, 1000) } }, getters: { doubleCountA(state) { return state.countA * 2 } } } const moduleB = { state: { countB: 0 }, mutations: { incrementB(state) { state.countB++ } }, actions: { incrementBAsync({ commit }) { setTimeout(() => { commit('incrementB') }, 1000) } }, getters: { doubleCountB(state) { return state.countB * 2 } } } const store = new Vuex.Store({ modules: { moduleA, moduleB } }) // used in the component this.$store.state.moduleA.countA // Get countA status in moduleA this.$store.commit('moduleA/incrementA') // triggers the incrementA mutation in moduleA this.$store.dispatch('moduleA/incrementAAsync') // Trigger the incrementAAsync action in moduleA