vuex

什么是vuex

vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。

什么时候使用vuex

在vue的组件化开发中,经常会遇到需要将当前组件的状态传递给其他组件。父子组件通信时,我们通常会采用 props + emit 这种方式。但当通信双方不是父子组件甚至压根不存在相关联系,或者一个状态需要共享给多个组件时,就会非常麻烦,数据也会相当难维护,这对我们开发来讲就很不友好。vuex 这个时候就很实用,虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 global event bus 就足够您所需了。但是,如果您需要构建是一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

vuex状态管理

"vuex"

view ——> (dispatch) Action ——>(commit)Mutations ——> (Mutate)State ——> view


"vuex"

vuex 初级实用版

count.vue内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
<div>
<h2>{{ msg }}</h2>
<hr>
<h3>{{ $store.state.count }} 通过computed赋值:{{ count }}</h3> //count通过computed对象定义
<div>
<button @click="$store.commit('plus')">+</button>
<button @click="addNumber">-</button> //通过methods定义方法函数
</div>
<div>以下通过action异步</div>
<div>
<button @click="$store.dispatch('addAction')">+</button>
<button @click="reduceAction">-</button> //通过通过methods定义方法函数
</div>
</div>
</template>

<script>
import store from '@/vuex/store'
export default {
data() {
return {
msg: 'Hello Vuex'
}
},

computed: { //count通过computed对象定义
count() {
return this.$store.state.count;
}
},
methods: {
addNumber() { //通过methods定义方法函数addNumber
return this.$store.commit("plus");
},
reduceAction() { //通过通过methods定义方法函数reduceAction
setTimeout(() => {
return this.$store.dispatch('minusAction')
},1000)
}
},
}

store
}
</script>

store.js文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {
count: 1
}

const mutations = {
plus(state) {
state.count ++;
},
minus(state) {
state.count --;
}
}

const getters = {
addDual: state => state.count += 2
}

const actions = {
addAction({commit}) {
setTimeout(
() => { context.commit('plus')},3000);
},
minusAction({commit}) {
setTimeout(
() => { context.commit('minus')},3000);
}
}
modules: {
a: modulesA
}

export default new Vuex.Store({
state,
mutations,
getters,
actions
})

vuex 包含有五个基本的对象:

  1. state:存储状态。也就是变量;组件调用方式:$store.state.count,在组件中也可以通过计算属性computed直接赋值:

    1
    2
    3
    4
    5
    computed: {
    count() {
    return this.$store.state.count;
    }
    }
  2. getters:派生状态。也就是set、get中的get,有两个可选参数:state、getters分别可以获取state中的变量和其他的getters。组件调用方式:$store.getters.addDual()。就和vue的computed差不多:

    1
    2
    3
    4
    5
    6
    // 通过getters每次累加2
    computed: {
    addDual() {
    return this.$store.state.count += 2;
    }
    }
  3. mutations:提交状态修改。也就是set、get中的set,这是vuex中唯一修改state的方式,但不支持异步操作。第一个参数默认是state。也可以向store.commit传入第二参数,也就是mutation的payload,组件调用方式:$store.commit(‘plus’)。和vue中的methods类似:

    1
    2
    3
    4
    5
    methods: {
    addNumber() {
    return this.$store.commit("plus");
    }
    }
  4. actions:和mutations类似。不过actions支持异步操作。第一个参数默认是和store具有相同参数属性的对象。组件调用方式:store.dispatch(‘addAction’)。和vue中的methods类似:

    1
    2
    3
    4
    5
    6
    7
    methods: {
    reduceAction() {
    setTimeout(() => {
    return this.$store.dispatch('minusAction')
    },1000)
    }
    }
  5. modules:store的子模块,内容就相当于是store的一个实例。调用方式和前面介绍的相似,只是要加上当前子模块名,如:$store.a.getters.xxx()。

辅助函数

在vue组件中使用时,我们通常会使用mapState、mapGetters、mapMutations、mapActions,然后就可以按照vue调用methods和computed的方式去调用这些变量或函数,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex';

export default {
computed: {
...mapState([
count
]),
...mapGetters([
addDual
])
},
methods: {
...mapMutations({
addNumber
}),
...mapActions([
reduceAction
])
}
};

vue-cli项目中使用vuex的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
├── index.html
├── main.js
├── components
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── state.js # 根级别的 state
├── getters.js # 根级别的 getter
├── mutation-types.js # 根级别的 mutations名称(官方推荐mutions方法名使用大写)
├── mutations.js # 根级别的 mutation
├── actions.js # 根级别的 action
└── modules
├── m1.js # 模块1
└── m2.js # 模块2

state.js示例:

1
2
3
4
5
const state = {
count: 1
}

export default state;

getters.js示例(我们一般使用getters来获取state的状态,而不是直接使用state):

1
2
3
export const addDual = (state) => {
return state.count += 2;
}

mutation-type.js示例(我们会将所有mutations的函数名放在这个文件里):

1
2
export const PLUS = 'PLUS';
export const MINUS = "MINUS"

mutations.js示例:

1
2
3
4
5
6
7
8
9
10
11
12
import {PLUS, MINUS} from './mutation-type';
import {

} from './mutation-types'

export default {
[PLUS] (state) {
state.count++
},
[MINUS] (state) {
state.count--
},

actions.js示例(异步操作、多个commit时):

1
2
3
4
5
6
7
8
9
10
11
12
13
import {PLUS, MINUS} './mutation-type';
export default {
plusAction({commit}) {
setTimeout(
() => {commit(PLUS)},3000);

},
minusAction({commit}) {
setTimeout(
() => { commit(MINUS)},3000);

},
};

modules–m1.js示例(如果不是很复杂的应用,一般来讲是不会分模块的):

1
2
3
4
5
6
export default {
state: {},
getters: {},
mutations: {},
actions: {}
};

index.js示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import vue from 'vue';
import vuex from 'vuex';
import state from './state';
import * as getters from './getters';
import mutations from './mutations';
import actions from './actions';
import m1 from './modules/m1';
import m2 from './modules/m2';

vue.use(vuex);

export default new vuex.Store({
state,
getters,
mutations,
actions,
modules: {
m1,
m2
},

最后将store实例挂载到main.js里面的vue上去就行了

1
2
3
4
5
6
7
import store from './store/index.js';

new Vue({
el: '#app',
store,
render: h => h(App)
});

Buy me a cup of coffee,thanks!