table of Contents
vuex
Shared state (data) management tool
installation
npm i vuex
Use in vue
Configure in main.js
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state:{
// 状态(数据)
count:0
}
});
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
After configuration, you can use the vue-devtool tool to view in the browser
F12 to open the console, vue-》vuex
- Generally, the configuration of vuex is placed in store.js, and then introduced in main.js
Configuration in store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state:{
count:0
}
})
export default store;
Get the state (data) of vuex in the component
After configuration, Vue.use(Vuex)
inject the state follower component into each sub-component
Sub-components can this.$store
access the state of vuex
this.$store
As an object, there are many functions in it
this.$store.state
Is the state of our configuration
this.$store.state.count
Get specific status
组件中改变了状态,那么也会影响到使用到这个状态的组件
Use in the view
direct{
{ $store.state.count }}
Write a long list in this way, then you can use it as the component's own attribute and use the calculated attribute to achieve it.
<template>
<div class="home">
首页
<button @click="$store.state.count++">点击</button>
<!-- {
{ $store.state.count }} -->
{
{ count }}
</div>
</template>
<script>
export default {
computed:{
count(){
return this.$store.state.count;
}
},
};
</script>
Writing in this way will still cause redundancy, because there may be many states.
Vuex helped us solve this problem.
// 需要引入
import {
mapState } from 'vuex';
export default {
computed:{
// count(){
// return this.$store.state.count;
// }
// mapState(['count']) 会返回一个计算函数
...mapState(['count'])
},
After the same name as the data in the component, the priority of data is higher. This is because we need to rename it. You can change the data name in data. If the data name in data participates in too much logic, then you can change the data in mapState. name
mapState({
// 重命名的数据变量 后面是一个函数,函数第一个参数是state,函数的返回值就是变量的值
storeCount:(state) => state.count;
// 如果不需要对仓库中的状态处理的话,可以简写
storeCount:'count'; //(state) => state.count;
})
getter
The getter is a calculated attribute of the store. The return value of the getter will be cached according to its dependencies
and will be recalculated only when its dependency value changes.
- use
Configure in store.js
const store = new Vuex.Store({
state:{
count:0,
studentList:[]
},
// 是复数 有多个getters,里面是函数,第一个参数是state
getters:{
doubleCount(state){
return state.count * 2;
},
// 可以返回一个函数
addCount(state){
return function(num){
return state.count + num;
}
}
},
})
Configured and used in the component like count, you can
{
{$store.getters.doubleCount }} in the view
- mapGetters helper function
Similar to mapState
Introduce mapGetters in the component
import {
mapGetters } from 'vuex';
computed:{
// count(){
// return this.$store.state.count;
// }
...mapState(['count']),
...mapGetters(['addCount','doubleCount'])
},
mutation
English means variation, change
In strict mode of vuex
To enable strict mode, only need to pass strict: true when creating the store
const store = new Vuex.Store({
//...
strict:true
})
在严格模式下,无论何时发生了状态变更且不是mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
更改vuex的store中的状态的唯一方法是提交mutation
One-way data flow in vuex
State -> view change -> mutation -> state
Development environment and release environment
Do not turn on strict mode in the release environment. Strict mode will deeply monitor the state tree to detect unqualified state changes. Make sure to turn off strict mode in the release environment to avoid performance loss.
const store = new Vuex.Store({
//...
strict: process.env.NODE_ENV !== 'production'
})
mutation use
In the store configuration
mutations:{
countIncrement(state){
// 变更状态
state.count++;
}
}
Submit in the component
methods:{
handleClick(){
this.$store.commit('countIncrement');
}
}
- mapMutation
methods:{
...mapMutations('countIncrement'),
handleClick(){
// this.$store.commit('countIncrement');
this.countIncrement();
}
}
-
Why not use mapMutation in computed, it returns a function.
-
The mutation changes the state according to the parameters passed at the time of submission
mutations:{
countIncrement(state,num){
// 变更状态
state.count += num;
}
}
methods:{
// ...mapMutations('countIncrement',10),
handleClick(){
// 第二个就是要传递的参数 一般写成一个对象
this.$store.commit('countIncrement',
{
num: Math.floor(Math.random()* 100;
}
);
// this.$store.commit('countIncrement',10);
// this.countIncrement();
}
}
If it is written as an object, then the mutations must be deconstructed
mutations:{
countIncrement(state,{
num}){
// 变更状态
state.count += num;
}
}
The second parameter in commit is professionally called payload.
The parameters in commit can be passed directly to an object
this.$store.commit({
// mutaion的函数名
type:'countIncrement',
// 数据
num:10
});
store.js
mutations: {
countIncrement(state, payload) {
// 变更状态
state.count += payload.num;
}
}
mutation configuration file
You can put the name of the mutation in a separate file, with the name in uppercase
mutation-types.js中
export const COUNT_INCREMENT = 'COUNT_INCREMENT';
import {
COUNT_INCREMENT
} from './mutation-types.js';
mutations: {
// countIncrement(state, payload) {
// // 变更状态
// state.count += payload.num;
// }
[COUNT_INCREMENT](state,payload){
state.count += payload.num;
}
}
Component
this.$store.commit({
// mutaion的函数名
type:'COUNT_INCREMENT',
// 数据
num:10
});
Mutations need to comply with Vue's response rules
When you need to add new properties to the object, you should use it, otherwise the view will not refresh
-
Vue.set (obj, 'newProp', 123);
-
Replace old objects with new ones, for example
state.obj = {
...state.obj,newProp:123}
[OBJ_B](state,payload){
Vue.set(state.obj,'b',2)
// state.obj = {...state.obj,b:2};
}
Form processing
When using v-model on the state of vuex, since the value of state will be directly changed, vue will throw an error.
If you want to use the two-way data function, you need to simulate one yourself, as follows:
mutation-types.js file
export const CHANGE_MSG = 'CHANGE_MSG';
import {
CHANGE_MSG} from 'mutation-types.js';
const store = new Vuex.Store({
state:{
msg:''
},
mutations:{
[CHANGE_MSG](state,{
value}){
state.msg = value;
}
}
})
<template>
<div>
<input :value="msg" @input="handleInput" />{
{ msg }}
</div>
</template>
<script>
import {mapState} from 'vuex';
import {CHANGE_MSG} from 'mutation-types.js';
export default {
computed:{
...mapState(['msg'])
},
methods:{
handleInput(e){
this.$store.commit(CHANGE_MSG,{value: e.target.value});
}
}
}
</script>
The above implementation method is a bit troublesome
It can also be achieved with the help of the get and set methods in the calculated properties
<template>
<div>
<input v-model='msg'/>{
{ msg }}
</div>
</template>
<script>
import {mapState} from 'vuex';
import {CHANGE_MSG} from 'mutation-types.js';
export default {
computed:{
// ...mapState(['msg']);
msg:{
get(){
return this.$store.state.msg;
},
set(value){
this.$store.commit(CHANGE_MSG,{value})
}
}
},
}
</script>
export const CHANGE_MSG = 'CHANGE_MSG';
import {
CHANGE_MSG} from 'mutation-types.js';
const store = new Vuex.Store({
state:{
msg:''
},
mutations:{
[CHANGE_MSG](state,{
value}){
state.msg = value;
}
}
})
The function in the mutation cannot be asynchronous
-
Asynchrony will cause debugging problems and cannot be traced. Vue will also report errors that cannot be changed outside the mutation. Asynchronous functions will be executed in the asynchronous queue.
-
action will solve this problem
Action
Action and mutation are similar, but there are two differences:
-
Action cannot directly change the state, but by submitting a mutation to change the state
-
Action can contain any asynchronous operation, and mutation cannot
action and function accepts a store instances of the same methods and properties of the context object, can be invoked directly context.commit
submit a mutation, or by context.getters
and context.state
acquired state and getters
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state){
state.count++;
}
},
actions:{
increment(context){
context.commit('increment');
}
}
})
How to use the action in the component, which needs to distribute the action
Distribute action
this.$store.dispatch('increment')
Off and map
- mapState calculated properties
- mapGetters calculated attributes
- mapMutations returns a function methods
- mapActions returns a function methods
Asynchronous operations
mutation submitted by action
actions: {
countIncrement(context) {
setTimeout(() => {
context.commit('increment');
}, 1000)
}
}
- Then how to know the end time of the asynchronous action, you can return a promise in the actions function.
actions: {
countIncrement(context) {
return new Promise((resolve,reject) => {
setTimeout(() => {
context.commit('increment');
resolve(12);
}, 1000)
})
}
}
When distributing, then a pop-up box will pop up
this.$store.dispatch('countIncrement').then(res=>{
alert('actions结束'+res);
});
Module
Previously, a single state number was used, and all the states of the application will be concentrated into a relatively large object.
So modules are here to solve this problem, vuex allows us to split modules (module). Each module has its own state, getter, mutation, and action.
const store = new Vuex.Store({
modules:{
module1,
module2
}
})
注意
- Only add the above module name when obtaining state, other normal use
- Get state:
this.$store.modulesName.xxx;
- Get the getter:
this.$store.getters.xxx;
- Submit mutation:
this.$store.commit(xxx);
- Distribute actin:
this.$store.dispatch(xxx);
- Corresponding can be obtained through mapstate, mapGetters, mapMutation, and mapAction, but mapState cannot be obtained. To achieve this, a namespace is required.
Namespaces
It can be namespace:true
made into a module with a namespace by adding .
Get state: this.$store.state.modulesName.xxx;
get getter: this.$store.getters['modulesName/xxx'];
submit mutation: this.$store.commit('modulesName/xxx');
distribute actin:this.$store.dispatch('modules/xxx');
Local state of the module
-
For the mutation and getter inside the module, the first parameter accepted is the local object of the module.
-
For actions inside the module, the local state is exposed through context.state, and the root node is context.rootState
-
For the getter inside the module, the root node state will be exposed as the third parameter