Vue状态(视图共享)管理:Vuex

设想一下,如果不用Vuex,我们应该如何在页面各组件之间传值?通过props、$emit在父子组件之间来回穿梭传值?抑或通过bus在组件之间共享值?无论哪种方式,都是极其麻烦或者可读性非常差的。而Vuex的引入很好的解决了这个问题,它把一些共享的属性(状态)集中的管理起来,使得你只需要关注Vuex中定义的state就可以了,state的变化会自动响应到引用了它的视图(页面组件),Vuex很好的解决了以下两个问题:
1、多个视图依赖于同一状态。
2、来自不同视图的行为需要变更同一状态。

一个简单的Vuex的示例如下:

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
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
state(){
return {
count: 0,
todos: [
{ id: 1, text: 'todo1', done: true },
{ id: 2, text: 'todo2', done: false }
]
}
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length;
},
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
},
mutations: {
increment (state) {
state.count++;
}
},
actions: {
},
modules: {
}
})

1、Vuex的核心

Vuex的核心部分包括:State、Getter、Mutation、Action、Module

  • State:vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state访问到它。
  • Getter:Getter相当于vue中的computed计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
  • Mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。提交mutation必须是同步的方式(不可以异步)。
  • Action:Action 类似于 mutation,不同在于:
    a、Action 提交的是 mutation,而不是直接变更状态。
    b、Action 可以包含任意异步操作。
    Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。Action 通过 store.dispatch 方法触发,如:
    1
    store.dispatch('increment')

Action不受同步的约束!我们可以在 action 内部执行异步操作:

1
2
3
4
5
6
7
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}

注:建议最好所有的Mutation操作都用action分发,这样如果业务发生变更(需要由同步变成异步的操作方式),你只需要更改store中的相关action定义就可以了,而不需要去修改引用它的业务代码。

  • Module:Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。分模块后更便于维护store,如果所有状态都放在一个store中会使得这个store过于臃肿,且不易于维护。

2、在视图(页面组件)中访问State、Getter、Mutation、Action

在页面视图中,我们可以分别使用this.$store.state、this.$store.getters访问State和Getter,使用this.$store.commit(‘xxx’) 提交 mutation,使用this.$store.dispatch(‘xxx’) 分发 action。但这样使用并不规范也不方便,vuex提供了相应的辅助函数:mapState、mapGetters、mapMutations、mapActions用来分别访问它们。示例如下:

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
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'

export default {
// ...
computed:{
...mapState({
// 箭头函数可使代码更简练
count: state => state.count,

// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',

// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
}),
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
},
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
}),
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}

3、示例demo

一个简单的Vuex的示例Demo,请访问https://github.com/johnnynie/vue-demos/tree/master/vuex-demos/demo1

posted @ 2020-05-11 00:38  前端客  阅读(638)  评论(0编辑  收藏  举报