VueX

Vuex的工作流程:

actions:支持异步操作

mutations:同步操作

安装和配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
state: {
msg: '以葫为种,不假外物'
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
store, // 可以通过this.$store在组件中访问
render: h => h(App)
}).$mount('#app')

在组件的template中使用,通过this.$store访问到。

1
2
3
4
5
<template>
<div id="app">
<HelloWorld :msg=this.$store.state.msg />
</div>
</template>

State的定义和使用

定义

定义同上。

mapState辅助函数

mapState可以简化代码,帮助生成计算属性。

1
2
3
4
5
6
7
import { mapState } from 'vuex'
export default {
name: 'App',
computed: {
...mapState(['msg']) // template可以通过this.msg拿到值。
}
}

另一种写法:

1
2
3
4
5
6
7
8
import { mapState } from 'vuex'
export default {
name: 'App',
computed: mapState({
msg: state => state.msg,
aliasMsg:'msg' // 同上,可以通过this.aliasMsg访问到。
})
}

如果想要在computed中访问到data中的值,必须使用普通函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default {
name: 'App',
data() {
return {
prefix: '不可颂其真名 ,'
}
},
computed: mapState({
msg: state => state.msg,
AliasMsg: 'msg',
// 下面函数的定义不能使用箭头函数
Hu(state) {
return this.prefix + state.msg
}
})
}

使用对象展开符和原本的computed进行合并。
下面这种情况,computed本身的Hu会被覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
computed: {
Hu() {
return this.prefix
},
...mapState({
msg: state => state.msg,
AliasMsg: 'msg',
Hu(state) {
return this.prefix + state.msg
}
})
}

Getter

场景:多个组件需要对同一个store中的数据做相同的filter操作。类似于组件内的computed。

定义

1
2
3
4
5
6
7
8
9
10
11
export default new Vuex.Store({
state: {
msg: '以葫为种,不假外物'
},
getters: {
// 定义getter
frefixMsg: state => {
return '颂我真名者,' + state.msg
}
}
})

访问

组件中访问。

1
2
3
4
5
6
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>{{ this.$store.getters.frefixMsg }}</h2>
</div>
</template>

getter嵌套使用

一个getter里面也可以接收其他getter作为第二个参数。但不可以递归调用自身。

1
2
3
4
5
6
7
8
getters: {
frefixMsg: state => {
return '颂我真名者,' + state.msg
},
AliasFixMsg: (state, getter) => {
return 'second' + getter.frefixMsg
}
}

getter传参【不会缓存】

1
2
3
4
5
getters: {
customMsg: (state) => (cm) => {
return cm + state.msg
}
}
1
2
3
4
5
<template>
<div class="hello">
<h2>{{ this.$store.getters.customMsg('葫天帝') }}</h2>
</div>
</template>

mapGetters辅助函数

将store中的getter映射到局部计算属性,同样支持别名。

1
2
3
4
5
6
7
8
9
10
import { mapGetters } from 'vuex'
export default {
name: 'HelloWorld',
props: {
msg: String
},
computed: {
...mapGetters(['customMsg'])
}
}

mutation【必须是同步!!!】

每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数。多个参数封装成对象作为mutation的第二个参数。

定义mutation

1
2
3
4
5
6
7
8
9
10
11
export default new Vuex.Store({
state: {
msg: '以葫为种,不假外物'
},
mutations: {
changeMsg(state, msg) {
state.msg = msg
}
}
})

组件中提交更新

1
2
3
updateMsg() {
this.$store.commit('changeMsg','葫,我的孩子,你在哪?')
}

对象风格的提交方式。data为commit传递的整个对象。

1
2
3
4
5
mutations: {
changeMsgObject(state, data) {
state.msg = data.msg
}
}
1
2
3
4
5
methods: {
updateMsgObject() {
this.$store.commit({ type: 'changeMsgObject', msg: '镇压!' })
}
}

mapMutations

使用mapMutations可以将this.$store.commit('xxx')映射为this.xxx

1
2
3
4
5
6
methods: {
updateMsg() {
this.$store.commit('changeMsg', '葫,我的孩子,你在哪?')
},
...mapMutations(['changeMsg'])
}
1
2
3
4
5
<template>
<div class="hello">
<button @click="changeMsg('善假于物')">点我修改数据</button>
</div>
</template>

Action【支持异步操作!!!】

  • Action提交的是mutation,而不是直接改变状态。
  • Action可以包含任意异步操作。

Action的定义

1
2
3
4
5
6
7
8
actions: {
// 多个参数通过对象来传递{msg,delay}
changeMsgDelay(context, { msg, delay }) {
setTimeout(() => {
context.commit('changeMsg', msg)
}, delay);
}
}

Action的派发

1
2
3
4
5
methods: {
asyncUpdate() {
this.$store.dispatch({ type: 'changeMsgDelay', msg: '吾以葫名,号令诸天', delay: 3000 })
},
}

mapActions辅助函数

辅助函数将组件的methods映射为store.dispatch调用。

1
2
3
methods: {
...mapActions(['changeMsgDelay'])
}
1
2
3
<template>
<button @click="changeMsgDelay({ msg: '吾以葫名,号令诸天', delay: 3000 })">点我修改数据</button>
</template>

组合Action

action可以返回一个promise,在dispatch之后使用then回调。

Moudle

基本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}

const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}

const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

// getters、actions、mutation都在全局范围内。

对于模块内部的mutation和getter,接收的第一个参数是模块的局部状态对象。
同样,对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为context.rootState。
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
},
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}

命名空间

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
模块具有更高的封装度和复用性,可以通过添加namespaced: true的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

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
const moudleA = {
namespaced: true,
state: {
anum: 0
},
getters: {
getAnum(state) {
return state.anum
}
},
mutations: {
changenum(state, num) {
state.num = num
}
},
actions: {
asyncChangenum(context, num) {
context.commit('changenum', num)
}
}
}
export default new Vuex.Store({
//..
modules: {
moudleA
}f
})

开启后:

命名空间的模块内访问全局

1
2
dispatch('someOtherAction', null, { root: true })
commit('someMutation', null, { root: true })

命名空间内注册全局action

1
2
3
4
5
6
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 'someAction'
}
}

简化辅助函数

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
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}

//or

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

computed: {
// 在 `some/nested/module` 中查找
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// 在 `some/nested/module` 中查找
...mapActions([
'foo',
'bar'
])
}

4.0新特性

全新的“useStore”组合式函数

1
2
3
4
5
6
7
import { useStore } from 'vuex'

export default {
setup () {
const store = useStore() // this.$store
}
}