Vex2.0 state management
In vue. js, two ways are provided to facilitate communication management for different application projects: 1. Small single-page projects adopt communication between components; 2. Second, the development of large single-page applications usually adopt vEX2.0 state mechanism to achieve communication.
In vue. js, the parent-child component relationship can be summarized as props Down, events up. The parent component passes data down to the child component through props, and the child component sends messages to the parent component through Events.
What is Vuex?
Vex is a state management mode developed specifically for vue.js applications. It uses centralized storage to manage the state of all components of the application, and the corresponding rules ensure that the state changes in a predictable one-way data flow.
- State, the data source that drives the application;
- Mutations action drives mutations (which must be a synchronous function) to update the store.state data source;
- Actions, in response to changes in state caused by user input on the view,
- Getters, which derives some state from the state in store.
Vex2.0 has several major changes
dispatch
: Indicates an intention for some event to occur (possibly as a side effect of an asynchronous operation), usually used to trigger an action
methods:{
Add : function(){
this.$store.dispatch('ADD',2).then(function(resp){
console.log(resp)
})
}
}
Copy the code
commit
: specifies a synchronization operation that will change the actual state, driving mutation to update state
actions:{ "ADD" : function(store , param){ return new Promise(function(resolve, reject) { store.commit('ADD',param) resolve("ok"); }}})
Copy the code
Complicated examples of calling asynchronous apis and distributing multiple mutations:
actions: {checkout ({commit, state}, products) {const savedCartItems = [...state.cart.added] Commit (types.checkout_request) // The shopping API accepts a successful callback and a failed callback shop.buyProducts(products, CHECKOUT_SUCCESS => commit(types.checkout_failure, savedCartItems)}}
Copy the code
Ps: Vu1.x triggers Action and mutation use Dispatch
2. Obtain Vuex state, computed and mapState in the Vue component
Since Vuex’s state store is reactive, the easiest way to read state from a Store instance is to return some state in a calculated property:
- Computed properties
Attributes are computed to solve the data operation of expressions in templates, and can be computed to cache decoupled code.
In Vuex, states in store instances can be read through computed computations. When store.state.count changes, the calculated attributes will be recomputed and the associated DOM will be updated.
// Create a Counter component // Global state singleton, const Counter = {template: '<div>{{count}}</div>', computed: {return store.state.count}}} // local state singleton, recommended, store register to the root instance const Counter = {template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
Copy the code
Every time store.state.count changes, the calculated property is refetched and an update to the associated DOM is triggered.
- MapState helper function
When a component needs to fetch multiple states, it can be repetitive and redundant to declare all those states as computed properties. To solve this problem, we can use the mapState helper function to help us generate calculated properties that will save you from pressing the key:
MapState import {mapState} from 'Vuex' export default {//... Computed: mapState({// Arrow function makes code more concise count: This.$store.state => state.count, // Pass string 'count' equal to 'state => state.count' countAlias: 'count', // To be able to get local state with 'this ', CountPlusLocalState (state) {return this.$store.state.count + this.localCount}})}
Copy the code
Use this.$store.dispatch(‘ XXX ‘) to distribute actions within the component, or use the mapActions helper function to map the component’s methods to store.dispatch calls (requiring store injection at the root node first).
import { mapActions } from 'vuex' export default { // ... methods: { ... MapActions (['increment' // maps this.increment() to this.$store.dispatch('increment')]),... MapActions ({add: 'increment' // map this.add() to this.$store.dispatch('increment')})}}
Copy the code
4. Combine Actions asynchronously
Actions are usually asynchronous. Store. dispatch can handle the Promise returned by the triggered Action’s callback function, and store.dispatch still returns a Promise knowing when the Action will end. It is easy to combine multiple actions to handle more complex asynchronous processes.
Active Previous asynchronous promise:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
Copy the code
Now a better way is to:
// Store the form actions: {//... actionB ({ dispatch, Commit}) {return dispatch('actionA'). Then (() => {commit('someOtherMutation')})}} // form inside component store.dispatch('actionA').then(() => { // ... })
Copy the code
With the upcoming async/await feature of JavaScript, we can combine actions like this
// 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
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 status
Copy the code
Local state of a module
For mutation and getters inside a module, the first argument received is the module’s local state object.
const moduleA = { state: { count: 0 }, mutations: {increment (state) {// where the 'state' object is the local state of the module state.count++}}, getters: { doubleCount (state) { return state.count * 2 } } }
Copy the code
Similarly, for actions within the module, the local state is exposed through context.state and the rootState is context.rootState:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
Copy the code
For getters inside the module, the root node state is exposed as a third parameter:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
Copy the code
By default, actions, mutations, and getters inside a module are registered in the global namespace — enabling multiple modules to respond to the same mutation or action. If you want your module to be more self-contained or reusable, you can make it a namespace module by adding Namespaced: True. When a module is registered, all its getters, actions, and mutations are automatically named according to the path the module was registered with. Such as:
Const store = new vuex. store ({modules: {account: {namespaced: true, // Module assets state: {... }, // module states are already nested, and using the 'namespaced' attribute doesn't affect them. Getters: {isAdmin () {... } // -> getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login')}, // nested modules modules: {// Inherit the parent module's namespace myPage: {state: {... }, getters: { profile () { ... } // -> getters['account/profile']}}, // further nested namespace posts: {namespaced: true, state: {... }, getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } } })
Copy the code
6. Dynamic module registration
After the store is created, you can register the module using the store.registerModule method:
// registerModule 'myModule' store.registerModule('myModule', {//... }) // Register nested modules 'nested /myModule 'store.registerModule(['nested', 'myModule'], {//... })
Copy the code
Can be used after store. State. MyModule and store state. Nested. MyModule access module.
References:
Vuex2.0 design