Introduction, installation and initialization
What is vuex
VueX is a state management tool for use in Vue project development. Vue provides a unified management tool - VueX for these values frequently used by multiple components. In a Vue project with VueX, we only need to define these values in VueX, which can be used in the components of the whole Vue project.
How to install vuex
npm installation
npm i vuex -s
How to use vuex
Add a new store folder under the root directory of the project, and create index js
This is the src folder of the project
│ App.vue │ main.js │ ├─assets │ logo.png │ ├─components │ HelloWorld.vue │ ├─router │ index.js │ └─store index.js
In the store JS file, introduce vuex and use vuex. Note that the variable names are uppercase Vue and vuex
//store.js import Vue from 'vue' import Vuex from 'vuex' //Mount Vuex Vue.use(Vuex) //Creating VueX objects const store = new Vuex.Store({ state:{ //The stored key value pair is the state to be managed name:'helloVueX' } }) export default store
Mount the store to the Vue instance of the current project
//main.js import store from './store' new Vue({ el: '#app', router, store, // Like router, mount the Vuex instance we created into this vue instance render: h => h(App) })
Using Vuex in components
For example, in app In Vue, we will display the name defined in state in the h1 tag
<template> <div id='app'> name: <h1>{{ $store.state.name }}</h1> </div> </template>
Or use it in component methods
methods:{ add(){ console.log(this.$store.state.name) } },
The specific usage will be described in detail below
Note: the emergence of vuex is to solve the communication problem between components. If an operation or data does not involve a public operation, but only a single component operation, do not store these status values or function s in vuex, because vuex will mount itself to all components, no matter whether the current component uses the contents or not, so this will in fact increase the loss of performance
Core content in VueX
In vuex, there are five basic objects by default:
- State: storage state (variable)
- getters: recompilation before data acquisition can be understood as the calculation attribute of state.
- Changes: changes the state and is synchronized. This is similar to the custom event in our component.
- actions: asynchronous operations.
- modules: a sub module of the store
Split into single file
If there are too many states and methods in the project, index JS files will look bloated and difficult to maintain. At this time, we can split state, getters, variations and actions into a single file, which is conducive to management
Here is the directory structure
store │ │ ├─index.js │ │ ├─state.js │ │ ├─getters.js │ │ ├─mutations.js │ │ └─actions.js
index.js
import Vue from 'vue'; import Vuex from 'vuex'; import state from './state'; import getters from './getters'; import mutations from './mutations'; import actions from './actions'; Vue.use(Vuex); export default new Vuex.Store({ state, mutations, actions, getters, });
In other files, you only need to export
state.js
export default { name:'hzw' };
mutations.js
export default { changeName(state, name) { state.name = name; }, };
getters.js
export default { realName(state) { return "full name:" + state.name }, };
actions.js
export default { changeName({ commit }, name) { return commit('changeName', name) } };
This makes it look more structured and easier to maintain
state and mapState
What is state
state(vuex) ≈ data (vue)
vuex's state and vue's data have many similarities. They are used to store some data, or state values These values will be loaded with two-way binding events between data and dom, that is, when the value changes, the dom update can be triggered
We're in state JS declares a state count with an initial value of 0, and then outputs it in the component
// state.js export default { count:'0' };
//In component <template> <div class="hello"> <h3>{{$store.state.count}}</h3> </div> </template>
The results are shown in the figure below
Note: Although there are many similarities between state and data, state is usually attached to the calculated calculation attribute of the sub component when it is used, which is conducive to responding to the sub component in time when the value of state changes If you use data to receive $store State can also receive values, but since this is only a simple assignment operation, the data in vue cannot listen to the change of state in state You can also use watch $store to solve this problem, but it's a little troublesome
Therefore, it is better to use computed to receive the state. As follows, the method of modifying the state will be learned later, and will be shown here first
//mutations.js export default { add(state, n = 0) { return (state.count += n) }, reduce(state, n = 0) { return (state.count -= n) } }
//In component <template> <div class="hello"> <h3>{{$store.state.count}}</h3> <div> <button @click="add(10)">increase</button> <button @click="reduce(10)">reduce</button> <div>computed:{{dataCount}}</div> <div>data: {{count}}</div> </div> </div> </template> <script> export default { name: 'HelloWorld', data () { return { dataCount: this.$store.state.count //Receive with data } }, computed:{ count(){ return this.$store.state.count //Receive with computed } }, methods: { add(n){ this.$store.commit('add',n); }, reduce(n){ this.$store.commit('reduce',n); } } } </script>
Then we click the Add button to see what happens. The results are as follows
It can be seen that the value received with data cannot respond to the update in time. Just use computed
Knowledge point: the initialization of Props, methods,data and computed is completed between beforeCreated and created.
What is mapState
Surface meaning: mapState is an auxiliary function of state
Practical effect: when a component needs to obtain multiple states, declaring these states as calculation attributes will be somewhat repetitive and redundant. To solve this problem, you can use the mapState helper function to help generate calculated properties
Usage: first import this auxiliary function
import { mapState } from 'vuex'
Then you can use mapState in computed
When using auxiliary functions such as mapState, if the name inside the component is consistent with that in vuex, it can be abbreviated to array.
//state.js export default { nickname:'Simba', age:20, gender:'male' };
//computed computed: mapState(['nickname','age','gender']) //The above sentence of code is equivalent to the following. Is it a lot simpler computed:{ nickname(){return this.$store.state.nickname} age(){return this.$store.state.age} gender(){return this.$store.state.gender} }
If you need to customize a calculation property, you need the expansion operator in es6:
data(){ return{ count:14 } } computed: { value(){ return "full name:" + this.coount/7 }, ...mapState(['nickname','age','gender']) }
getters and mapGetters
What are getters
Getters: for recompilation before data acquisition, the return value of getters will be cached according to its dependency, and will be recalculated only when its dependency value changes. To put it bluntly, it is about equal to vue's computed. You can use getters like computed. Of course, there are differences between the two
How to use getters
The method in getters has two default parameters
- State the state object in the current VueX object
- Getters the current getters object, which is used to use other getters under getters
//state.js export default { name:'simba', age:'20' }; //getters.js export default { // The first parameter is state realName(state) { return "full name:" + state.name }, // The second parameter can access getters nameAndAge(state, getters) { return "Age:" + state.age +";"+ getters.realName } };
How to access getters
Access through properties
getter will be exposed as store Getters object, we can access these values in the form of attributes:
store.getters.realName// ->Name: simba
Note: getter s are cached as part of Vue's responsive system when accessed through attributes.
Access by method
We can pass parameters to getters by asking getters to return a function. This is very useful when querying the array in the store.
state:{ todos:[ { id:2, text:'...', done: false } ] }, getters: { getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
Note: when accessing a getter through a method, it will be called every time without caching the results.
Use in components
We passed this in computed$ store. getters. XXX to bind a calculation property
//In component <template> <div class="hello"> <div> <div>{{message}}</div> <div>{{message2}}</div> </div> </div> </template> computed:{ message(){ return this.$store.getters.realName }, message2(){ return this.$store.getters.nameAndAge; } },
The results are as follows:
What is mapGetters
The mapGetters auxiliary function only maps getters in the store to local calculation properties:
Usage: first import this auxiliary function
import { mapGetters } from 'vuex'
Then you can use mapGetters in computed
computed: { ...mapGetters({ message: "realName", message2: "nameAndAge" }) },
Is it a lot simpler? If the name of the calculated attribute is the same as that of getters, you can also use the shortened form of array
computed: { ...mapGetters(["realName","nameAndAge"]) },
mutation and mapMutation
What is mutation
mutation is a collection of methods for operating state data, such as modifying, adding, deleting, and so on. mutation usually stores some methods to modify the state synchronously
Note: the only way to change the state in Vuex's store is to submit the mutation.
How to use mutation
The changes method has a default formal parameter: Change ([state] [, payload])
- State the state in the current VueX object
- Payload payload (the parameter passed when the method is called)
//state.js export default { name:'Han Zhiwei' }; //mutations.js export default { changeName(state, name) { state.name = name; }, };
We need to call mutation like this
this.$store.commit('changeName','Wu Yanzu')
For example, we modify the name attribute in the methods of the component
methods: { changeName(name){ this.$store.commit('changeName',name); }, } //Call the changeName method mounted(){ this.changeName('Wu Yanzu') }
When multiple parameter submissions are required, they can be placed in an object
this.$store.commit('changeName',{firstName:'han',lastName:'zhiwei'})
You can also pass parameters in another way
this.$store.commit({ type:'changeName', payload:{ firstName:'han', lastName:'zhiwei' } })
What is mapMutation
The mapMutation auxiliary function simply maps the mutation in the store to the component methods
Usage: first import this auxiliary function
import { mapMutation} from 'vuex'
Then you can use mapMutation in methods
methods:{ ...mapMutations({ changeName:'changeName', }) }
This code is equivalent to the following paragraph
changeName(payLoad){ this.$store.commit('changeName',payLoad) }
If the method name is the same as the mutation name, it can be abbreviated as follows
methods:{ ...mapMutations(['changeName']) }
You can also use constants instead of the mutations event type
Under the store folder, create a new mutation types JS file
//mutation-types.js export const ADD_AGE = 'ADD_AGE' //mutations.js import * as types from './mutation-types'; export default { [types.ADD_AGE](state, payLoad) { state.age += payLoad.number } } //js part of component ...mapMutations([types.ADD_AGE]),
But this is not very commonly used. Just know this knowledge point
Add or delete members in state
Now that we have talked about how to modify the value of state, by the way, how to add or delete members in state
Vue.set sets the value of a member for an object. If it does not exist, it will be added
Vue.set(state,"age",22)
Vue.delete delete member
Vue.delete(state,'age')
actions and mapActions
What is actions
The asynchronous operation directly in the mutation method may cause data invalidation. Therefore, Actions is provided for asynchronous operations, similar to axios requests. Finally, the value in state is modified by submitting the mutation method.
How to use actions
The method in Actions has two default parameters: action ([context] [, payload])
- The context object contains dispatch commit state getters rootState. You can use the deconstruction assignment of es6 to make it more explicit {commit}
- Payload payload (the parameter passed when the method is called)
Take an example. After one second, submit mutation to modify the name attribute in state
//state.js export default { name:'Han Zhiwei' }; //mutations.js export default { changeName(state, name) { state.name = name; }, }; //actions.js export default { asyncChangeName({ commit } ,name) { setTimeout(() => { commit('changeName',name); }, 1000); }, };
We need to call action like this
this.$store.dispatch('asyncChangeName','Wu Yanzu')
For example, we modify the name attribute in the methods of the component
methods: { changeName(name){ this.$store.dispatch('asyncChangeName',name); }, } //Call the changeName method mounted(){ this.changeName('Wu Yanzu') }
Another action can also be called in action
//actions.js export default { asyncChangeName({ dispatch }) { setTimeout(() => { dispatch('anotherAction'); }, 1000); }, anotherAction(){ console.log('the other one action Called') } };
You can also pass in state and rootState in action. As for what is rootState, you will know when you learn modular modules
//actions.js export default { action({ state }) { setTimeout(() => { console.log(state.name) }, 1000); }, anotherAction({ rootState }){ setTimeout(() => { console.log(rootState.name); }, 1000); } };
The parameters of actions are the same as that of mutation
this.$store.dispatch('changeName',{firstName:'han',lastName:'zhiwei'})
What is mapActions
The mapActions helper function simply maps the actions in the store to the component methods
Usage: first import this auxiliary function
import { mapActions} from 'vuex'
Then you can use mapActions in methods
methods:{ ...mapActions({ changeName:'changeName', }) }
This code is equivalent to the following paragraph
changeName(payLoad){ this.$store.dispatch('changeName',payLoad) }
If the method name is the same as the actions name, it can be abbreviated as follows
methods:{ ...mapActions(['changeName']) }
modules modularization
What are modules
When the project is huge and has many states, the modular management mode can be adopted. Vuex allows us to split the store into modules. Each module has its own state, mutation, action and getter.
Initialize modules
Previously, we learned how to index vuex JS file is split into a single file for management, so we still manage all modules in a single file split. The directory structure is as follows
store │ ├─index.js │ ├─state.js │ ├─getters.js │ ├─mutations.js │ ├─actions.js │ └─modules │ ├─moduleA // The structure of moduleA is the same as that of moduleB │ └─moduleB │ ├─index.js │ ├─state.js │ ├─getters.js │ ├─mutations.js │ └─actions.js
1. First root index JS not only introduces its own state, getters, variations and actions, but also introduces the index of two modules JS and export modules in export
import Vue from 'vue'; import Vuex from 'vuex'; import state from './state'; import getters from './getters'; import mutations from './mutations'; import actions from './actions'; import moduleA from './modules/moduleA/index'; import moduleB from './modules/moduleB/index'; Vue.use(Vuex); export default new Vuex.Store({ state, mutations, actions, getters, modules: { moduleA, moduleB, }, });
2. In the index of module a JS to import the state, getters, variations and actions of moduleA Moduleb is the same
Note: getter, mutation and action are registered in the global namespace by default, so we can use them by default as using the root state, which will lose the meaning of modularization, so we need to use them in the index of the module JS add named: true to make it a module with namespace. When a module is registered, all its getters, actions and mutations will be automatically named according to the path of module registration.
import state from './state'; import getters from './getters'; import mutations from './mutations'; import actions from './actions'; const moduleA = { namespaced: true, state: state, getters: getters, mutations: mutations, actions: actions, }; export default moduleA ;
3. The state, getters, variations and actions under module a are the same as those learned before. Just export them
//state.js export default { name:'hzw' }; //mutations.js export default { changeName(state, name) { state.name = name; }, }; //and so on
How to define in modularity
state
Write normally in their respective state JS
getter
getter will have three parameters, the first is the state in the module, the second is getters in the module, and the third is the root node state rootState
//getters.js export default { nameAndAge(state, getters, rootState) { return "Age:" + state.age +";"+ getters.realName + "" + rootState.name } };
mutation
The first parameter passed in by mutation is also the state in the module, which is actually the same as when the root state defines mutation
export default { //The state here is the local state of the module changeName(state, name) { state.name = name; }, };
actions
For action, the context object is only passed in. The state attribute in this object refers to the state in the module, and the rootState refers to the root state, as shown below
export default { changeName({ state,rootState }) { console.log(state.name) console.log(rootState .name) } };
How to develop in modularity
1. state acquisition
This requires adding a module name before the original state name to get the objects in the module.
this.$store.state.moduleA.name;
The same is true for auxiliary functions. Name is preceded by a module name
...mapState({ name: state => state.moduleA.name, }) //Abbreviation ...mapState('moduleA',['name']),
Getting the status of the root node is the same as before. You do not need to add module name or root
...mapState(['name']),
2. Get Getters
This also needs to add a module name before the original state name to get the objects in the module.
getters in the root state do not need to add a module name
store.getters.moduleA.realName //The first parameter of the map function also needs to be added with the module name computed: { //Get getters under moduleA ...mapGetters("moduleA",["realName","nameAndAge"]) //Get getters in root state ...mapGetters(["realName"]) },
3. Call mutation and action
According to the calculation of state and getters, the module name must also be added when calling the mutation and action in the module
You do not need to add a module name when calling the mutation and action in the root state
methods:{ //Call the action under module A ...mapActions('moduleA',['changeName']) //Call the mutation under module A ...mapMutation('moduleB',['changeName']) //Call action in root state ...mapActions(['changeName']) //Call mutation in root state ...mapMutation(['changeName']) }
4. It should be noted that {root:true} should be passed as the third parameter when the action in the module calls the action and mutation in the root state
//Actions under moduleA js export default { AsyncChangeName({ commit } ,name) { setTimeout(() => { //It calls the mutation in the root state commit('changeName',name,{ root: true }); //The action in the root state is called dispatch('changeName',name,{ root: true }); }, 1000); }, };
5. Register the action in the module as global
This feeling conflicts with the modular design and is not commonly used. Just know this knowledge. When declaring an action, add root:true and put the definition of the action into the hanler function, as follows:
//actions.js export default { globalAction:{ root:true, handler({ commit } ,name) { setTimeout(() => { commit('changeName',name); }, 1000); }, } };
At this point, you can use vuex for development tasks!
Make an advertisement
This is my project of an open source collection website
Project address 👉👉 Click to enter , it can be directly set as the browser home page or desktop shortcut for use. I am using it and maintain it for a long time.
Completely open source, you can research and secondary development at will. Of course, you are welcome to order a Star ⭐⭐⭐
👉👉Source code link (gitee) 👉👉Source code link (github)
Link integration
🔊 Project preview address (GitHub Pages): 👉👉 https://alanhzw.github.io
🔊 Project preview alternate address (own server): 👉👉 http://warbler.duwanyu.com
🔊 Source address (gitee): 👉👉 https://gitee.com/hzw_0174/warbler-homepage
🔊 Source code address (github): 👉👉 https://github.com/alanhzw/WarblerHomepage
🔊 My blog: 👉👉 https://www.duwanyu.com