1, the preface
Recently, I reviewed the vUE family bucket, and it was more impressive to watch it again, so I specially recorded it (vuex version of this article is V3.x).
2. What is Vuex
Vuex is a state management mode developed specifically for vue.js. It uses centralized storage to manage the state of all components and rules to ensure that the state changes in a predictable way (global variables, as I understand them).
3. Description of 5 major attributes
state
Object type, similar to the instance’s data property, that holds data
getters
Object type, similar to instance computed property computed
mutations
Object type, similar to instance methods, but unable to handle asynchronous methods
actions
Object types, similar to instance methods, can handle asynchronous methods
modules
Object type. When there is a lot of state content, it is divided into small modules by using this attribute. Each module has its own state, mutation, action and getter
4, the state
Data stored in state follows the same rules as data in Vue instances and must be pure objects.
4.1 Direct Access
this.$store.state.xxx
Copy the code
4.1 Using mapState Mapping
<template>
<div id="communication">
<p>Count: {{getCount}}</p>
<p>School: {{getSchool(' I am a parameter ')}}</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Vuex'.data() {
return {
date: 1998}},computed: {
...mapState({
// mapState passes state as the first argument by default
getCount: state= > state.count,
getSchool(state) {
return (val) = > {
return state.school + val + this.date
}
}
})
},
mounted() {
// Take the value directly
console.log(this.$store.state.count)
}
}
</script>
Copy the code
5, getters
The return value of the getter is cached based on its dependency and recalculated only if its dependency value changes, and it accepts state as its first argument by default, or other getters as its second argument (as in the following example)
5.1 First define getters in VUEX
export default new Vuex.Store({
state: {
count: 0.school: 'Tsinghua University'
},
getters: {
// Return the state value after processing
getValue(state) {
return state.count + '! '
},
// Return the state value after calling its own getters processing
getGetters(state, getters) {
return state.school + getters.getValue
},
// The value that is processed after receiving an external argument (when accessed through a method, the call is made each time, without caching the result)
getParam(state) {
return (param) = > {
return state.school + param
}
}
},
mutations: {},
actions: {},
modules: {}})Copy the code
5.2 Obtaining the Value Directly
/ / value
console.log(this.$store.getters.getGetters)
// Pass the parameter value
console.log(this.$store.getters.getParam('param'))
Copy the code
5.3 Mapping using mapGetters
<template>
<div id="communication">
<p>Count: {{getGetters}}</p>
<p>School: {{getParam(date)}}</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'Vuex'.data() {
return {
date: 1998}},computed: {
...mapGetters([
'getGetters'.'getParam'])},mounted() {
// Take the value directly
console.log(this.$store.getters.getGetters)
console.log(this.getParam(this.date))
}
}
</script>
Copy the code
6, Mutation
Change the value in store by calling this. codestore.mit (‘ XXX ‘), calling the methods in mutation
6.1. Register the event on mutations first
export default new Vuex.Store({
state: {
count: 0.school: 'Tsinghua University'
},
getters: {},
mutations: {
// Default state as the first argument
handleAdd(state) {
state.count++
},
// Accept input
handleChange(state, value) {
state.school = value
}
},
actions: {},
modules: {}})Copy the code
6.2. Call the commit method in the component to modify the value
<template>
<div id="communication">
<p>Count: {{count}}</p>
<el-button @click="handleStoreAdd">increase</el-button>
<el-button @click="handleStoreChange">The ginseng</el-button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Vuex'.data() {
return {
school: 'Wuhan University'}},computed: {
...mapState([
'count'])},methods: {
// Call the modification
handleStoreAdd() {
this.$store.commit('handleAdd')},// Pass the parameter modification
handleStoreChange() {
this.$store.commit('handleChange'.this.school)
}
}
}
</script>
Copy the code
6.3. Use constants to define method names
Create a new file, mutation-types.js, define constants for method names, and export them
export const ADD_COUNT = 'ADD_COUNT'
export const CHANGE = 'CHANGE'
Copy the code
In the store
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0.school: 'Tsinghua University'
},
getters: {},
mutations: {
// Default state as the first argument
[MT.ADD_COUNT](state) {
state.count++
},
// Accept input
[MT.CHANGE](state, value) {
state.school = value
}
},
actions: {},
modules: {}})Copy the code
In the component
<template>
<div id="communication">
<p>Count: {{count}}</p>
<el-button @click="handleStoreAdd">increase</el-button>
<el-button @click="handleStoreChange">The ginseng</el-button>
</div>
</template>
<script>
import { mapState } from 'vuex'
import * as MT from '.. /.. /store/mutation-types'
export default {
name: 'Vuex'.data() {
return {
school: 'Wuhan University'}},computed: {
...mapState([
'count'])},methods: {
// Call the modification
handleStoreAdd() {
this.$store.commit(MT.ADD_COUNT)
},
// Pass the parameter modification
handleStoreChange() {
this.$store.commit(MT.CHANGE, this.school)
}
}
}
</script>
Copy the code
6.4. Use mapMutations mapping
<template>
<div id="communication">
<p>Count: {{count}}</p>
<p>Count: {{school}}</p>
<el-button @click="handleStoreAdd">increase</el-button>
<el-button @click="handleStoreChange(schools)">The ginseng</el-button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '.. /.. /store/mutation-types'
export default {
name: 'Vuex'.data() {
return {
schools: 'Wuhan University'}},computed: {
...mapState([
'count'.'school'])},methods: {
...mapMutations({
handleStoreAdd: MT.ADD_COUNT,
handleStoreChange: MT.CHANGE
})
}
}
</script>
Copy the code
7, the Action
Note that actions commit mutation, not direct change state, and can contain arbitrary asynchronous operations
7.1, defined in store
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0.school: 'Tsinghua University'
},
getters: {},
mutations: {
// Default state as the first argument
[MT.ADD_COUNT](state) {
state.count++
},
// Accept input
[MT.CHANGE](state, value) {
state.school = value
}
},
actions: {
add(context) {
context.commit(MT.ADD_COUNT)
}
},
modules: {}})Copy the code
7.2, used in components
<template>
<div id="communication">
<p>Count: {{count}}</p>
<el-button @click="actionAdd">increase</el-button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '.. /.. /store/mutation-types'
export default {
name: 'Vuex'.data() {
return {
schools: 'Wuhan University'}},computed: {
...mapState([
'count'.'school'])},methods: {
...mapMutations({
handleStoreAdd: MT.ADD_COUNT,
handleStoreChange: MT.CHANGE
}),
// Call the action method with $store.dispatch
actionAdd() {
this.$store.dispatch('add')}}}</script>
Copy the code
7.3. Use mapActions mapping
import { mapActions } from 'vuex'
methods: {
...mapActions([
'moduleFn'])}Copy the code
or
import { mapActions } from 'vuex'
methods: {
...mapActions([
fn: 'moduleFn'])}Copy the code
7.4. Simplified writing
The Action accepts a context parameter object with the same methods and properties as the store instance, so you can submit a mutation by calling context.mit. Or get state and getters from context.state and context.getters, which can be simplified using ES6 deconstruction.
actions: {
add({ commit, state }) {
commit(MT.CHANGE, state.school)
}
}
Copy the code
7.5. Perform asynchronous operations
In vuex
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
getters: {},
mutations: {
// Default state as the first argument
[MT.ADD_COUNT](state) {
state.count++
}
},
actions: {
add({ commit }) {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
commit(MT.ADD_COUNT)
resolve()
}, 1000)})}},modules: {}})Copy the code
Use async/await or then/catch to handle async in components
<template>
<div id="communication">
<p>Count: {{count}}</p>
<el-button @click="actionAdd">increase</el-button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '.. /.. /store/mutation-types'
export default {
name: 'Vuex'.data() {
return {
schools: 'Wuhan University'}},computed: {
...mapState([
'count'.'school'])},methods: {
...mapMutations({
handleStoreAdd: MT.ADD_COUNT,
handleStoreChange: MT.CHANGE
}),
// Call the action method with $store.dispatch
async actionAdd() {
await this.$store.dispatch('add')
console.log(1998)}}}</script>
Copy the code
Eight Modules
When the application becomes very complex, the Store object can become quite bloated. At this point, the Store can be split into modules, each with its own state, mutation, action, getter, and even nested submodules, split from top to bottom in the same way.
8.1. Preparation
Create modulesa. js, modulESB.js in the Modules folder under the Store directory, as shown below
Write state, mutation, action, and getter for the local module in modulesa.js and export it
const moduleA = {
state: () = > ({
a: 'I am moduleA'
}),
getters: {},
mutations: {},
actions: {}}export default moduleA
Copy the code
It’s then imported into the store index.js and thrown into the Modules object
import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
getters: {},
mutations: {},
actions: {},
modules: {
moduleA,
moduleB
}
})
Copy the code
8.2, use the module state injected in modules
Used directly in components
this.$store.state.moduleA.xxx
Copy the code
Use mapState mapping in components
<span>{{ moduleA.xxx }}</span>
import { mapState } from 'vuex'
computed: {
...mapState([
'moduleA'])}Copy the code
8.3, use modules to inject module getters
Used directly in components
this.$store.getters.getModuleA
Copy the code
Use mapState mapping in components
<p>{{ getModuleA }}</p>
import { mapGetters } from 'vuex'
computed: {
...mapGetters([
'getModuleA'])}Copy the code
The getters inside the module, and the parameters state and getters it accepts, are the module’s local state objects, while the state of the root node is exposed as the third parameter rootState
const moduleA = {
getters: {
getModuleA(state, getters, rootState) {
return state.xxx + The '-' + rootState.xxx
}
}
}
Copy the code
If you need to take parameters
const moduleA = {
getters: {
getModuleA(state, getters, rootState) {
return (value) = > {
return state.a + The '-' + value
}
}
}
}
Copy the code
8.4, use mutations in Modules to inject the module
Used directly in components
this.$store.commit('setModuleA') | |this.$store.commit('setModuleA'.'parameters')
Copy the code
Use mapMutations mapping in the component
import { mapMutations } from 'vuex'
methods: {
...mapMutations([
openFn: 'setModuleA'])}Copy the code
Mutations inside the module, the first parameter state accepted by default is the local state object of the module
const moduleA = {
mutations: {
setModuleA(state) {
state.xxx += 'xxx'}}}Copy the code
If you need to take parameters
const moduleA = {
mutations: {
setModuleA(state, value) {
state.xxx += value
}
}
}
Copy the code
8.5. Use actions in Modules to inject the module
Used directly in components
this.$store.dispatch('xxx')
Copy the code
Use mapActions mapping in the component
import { mapActions } from 'vuex'
methods: {
...mapActions([
'moduleA'])}Copy the code
Or rename it
import { mapActions } from 'vuex'
methods: {
...mapActions({
fn: 'moduleA'})}Copy the code
For actions within the module, the local state is exposed through context.state and the rootState is context.rootstate
const moduleA = {
// ...
actions: {
fn ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2= = =1) {
commit('increment')}}}}Copy the code
8.6, namespaces
By default, actions, mutation, and getters within a module are registered in the global namespace, allowing multiple modules to respond to the same mutation or action. If you want your modules to be more encapsulation and reusable, you can make them namespaced by adding namespaced: True to them. When a module is registered, all its getters, actions, and mutations are automatically named according to the path the module was registered with.
8.6.1, use
First add namespaced: true to the moduleb.js module
const moduleB = {
namespaced: true.state: () = > ({
b: 'I am moduleB'
}),
mutations: {},
actions: {},
getters: {}}export default moduleB
Copy the code
In store index.js
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'
export default new Vuex.Store({
state: {},
getters: {},
mutations: {},
actions: {},
modules: {
moduleA,
moduleB
}
})
Copy the code
If you use a namespace in a component, you need to use the same space name as mapState, mapGetters, mapMutations, and mapActions.
<script>
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
name: 'Vuex'.data() {
return{}},computed: {
// Data for the moduleA module is injected here. mapState('moduleA'['a'
]),
// If you need to inject the moduleB module, write another one. mapState('moduleB'['b'])},mounted() {
// Use it directly
console.log(this.$store.state.moduleA.a)
console.log(this.$store.state.moduleB.b)
},
methods: {}
}
</script>
Copy the code
8.6.2, access global content within a module with namespaces
If you want to use the global state and getter, rootState and rootGetters are passed into the getter as the third and fourth arguments, and the action is passed into the context object’s properties. To distribute action or commit mutation within the global namespace, pass {root: true} as the third argument to Dispatch or COMMIT
const moduleA = {
namespaced: true.state: () = > ({
a: 'I am moduleA'
}),
getters: {
getModuleA(state, getters, rootState, rootGetters) {
// Use state or getters for the global namespace
return state.a + rootState.count
}
},
mutations: {
setModuleA(state) {
console.log(state.a)
}
},
actions: {
addM({ state, commit, dispatch, rootState, rootGetters }) {
console.log(rootState)
console.log(rootGetters)
// Call the global namespace method
dispatch('rootFunction'.null, { root: true})}}}export default moduleA
Copy the code
Register global actions in namespaced modules
To register a global action in a namespaced module, add root: true and place the action definition in the handler function, where the first namespacedContext argument is the Context argument in the action
const moduleA = {
namespaced: true.state: () = > ({
a: 'I am moduleA'
}),
getters: {},
mutations: {},
actions: {
rootFn: {
root: true.handler(namespacedContext, param) {
console.log(namespacedContext.state)
}
}
}
}
export default moduleA
Copy the code
If you think it is helpful, I am @pengduo, welcome to like and follow the comments; END
The articles
- Use NVM to manage node.js version and change NPM Taobao image source
- Enumerative JS practical and powerful operator & operator
- Wechat small program to achieve search keyword highlighting
- Env files are used in vUE to store global environment variables and configure vUE startup and package commands
- More detailed! Vue’s nine ways of communication
Personal home page
- CSDN
- GitHub
- Jane’s book
- Blog garden
- The Denver nuggets