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:
- The Action commits mutation rather than a direct state change.
- 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