Vuex 四大核心辅助函数详解
Vuex 是 Vue.js 应用程序的状态管理模式和库。当我们的应用逐渐复杂,组件之间共享和传递状态变得困难时,Vuex 提供了一个集中的存储来管理所有组件的状态。为了更方便地在组件中使用 Vuex store 中的状态 (state)、取值器 (getters)、变更 (mutations) 和动作 (actions),Vuex 提供了这些辅助函数。它们的主要目的是简化模板代码,减少冗余。
🗺️ mapState
mapState 辅助函数用于帮助我们方便地在组件的计算属性 (computed) 中映射 store 中的 state。
🧩 不用 mapState
当不使用 mapState 时,我们需要为每一个需要从 store 中读取的状态手动创建一个计算属性。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <template> <div> <p>Count: {{ count }}</p> <p>Message: {{ message }}</p> <p>User: {{ user.firstName }} {{ user.lastName }}</p> </div> </template>
<script> export default { computed: { // 手动定义计算属性来获取 store 中的 state count() { return this.$store.state.count; // 直接访问 $store.state }, message() { return this.$store.state.message; // 直接访问 $store.state }, user() { return this.$store.state.user; // 直接访问 $store.state } } }; </script>
|
注释说明:
- 在
computed 对象中,我们为 count、message 和 user 分别定义了计算属性。
- 每个计算属性都返回
this.$store.state 中对应的状态值。
✅ 用了 mapState
使用 mapState 后,代码会变得更加简洁。它可以接收一个数组或一个对象作为参数。
1. 传递字符串数组:
当映射的计算属性的名称与 state 子树的名称相同时。
代码段
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
| <template> <div> <p>Count: {{ count }}</p> <p>Message: {{ message }}</p> <p>Local Computed: {{ localComputed }}</p> </div> </template>
<script> import { mapState } from 'vuex';
export default { data() { return { localData: '这是局部数据' }; }, computed: { // 局部计算属性 localComputed() { return this.localData.toUpperCase(); }, // 使用 mapState 辅助函数将 store 中的 state 映射到局部计算属性 ...mapState([ 'count', // 映射 this.count 为 store.state.count 'message' // 映射 this.message 为 store.state.message ]) } }; </script>
|
注释说明:
- 我们从
vuex 导入 mapState 函数。
- 使用对象展开运算符 (
...) 将 mapState 返回的对象混入到 computed 对象中。
mapState(['count', 'message']) 会生成 { count() { return this.$store.state.count }, message() { return this.$store.state.message } }。
2. 传递对象:
当映射的计算属性的名称与 state 子树的名称不同,或者需要更复杂的取值时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <p>Current Count: {{ currentCount }}</p> <p>App Message: {{ appMessage }}</p> <p>Full Name: {{ fullName }}</p> </div> </template>
<script> import { mapState } from 'vuex';
export default { computed: { ...mapState({ currentCount: 'count', // 将 this.currentCount 映射为 store.state.count appMessage: state => state.message, // 可以使用函数进行更灵活的映射 fullName: state => `${state.user.firstName} ${state.user.lastName}` // 访问深层嵌套的状态 }) } }; </script>
|
注释说明:
currentCount: 'count' 表示将组件内的计算属性 currentCount 映射到 Vuex store 中的 state.count。
appMessage: state => state.message 和 fullName: state => ... 展示了如何使用函数来获取 state,这提供了更大的灵活性,例如当 state 的值需要计算或来自嵌套对象时。
📊 mapGetters
mapGetters 辅助函数用于将 store 中的 getters 映射到组件的计算属性 (computed) 中。Getters 可以看作是 store 的计算属性。
🧩 不用 mapGetters
不使用 mapGetters 时,你需要为每个 getter 手动创建计算属性。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <div> <p>Doubled Count: {{ doubledCountValue }}</p> <p>Welcome: {{ welcomeText }}</p> </div> </template>
<script> export default { computed: { // 手动定义计算属性来获取 store 中的 getter doubledCountValue() { return this.$store.getters.doubledCount; // 通过 $store.getters 访问 }, welcomeText() { return this.$store.getters.welcomeMessage; // 通过 $store.getters 访问 } } }; </script>
|
注释说明:
doubledCountValue 和 welcomeText 计算属性分别从 this.$store.getters 获取对应的 getter 值。
✅ 用了 mapGetters
使用 mapGetters 可以简化这个过程。它也支持数组和对象两种形式。
1. 传递字符串数组:
当映射的计算属性的名称与 getter 的名称相同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <div> <p>Doubled Count: {{ doubledCount }}</p> <p>Welcome: {{ welcomeMessage }}</p> </div> </template>
<script> import { mapGetters } from 'vuex';
export default { computed: { // 使用 mapGetters 辅助函数将 store 中的 getters 映射到局部计算属性 ...mapGetters([ 'doubledCount', // 映射 this.doubledCount 为 store.getters.doubledCount 'welcomeMessage' // 映射 this.welcomeMessage 为 store.getters.welcomeMessage ]) } }; </script>
|
注释说明:
mapGetters(['doubledCount', 'welcomeMessage']) 会生成相应的计算属性,它们的值来源于 Vuex store 中的同名 getters。
2. 传递对象:
当映射的计算属性的名称与 getter 的名称不同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <p>Calculated Double: {{ calcDouble }}</p> <p>Greeting: {{ greeting }}</p> </div> </template>
<script> import { mapGetters } from 'vuex';
export default { computed: { ...mapGetters({ calcDouble: 'doubledCount', // 将 this.calcDouble 映射为 store.getters.doubledCount greeting: 'welcomeMessage' // 将 this.greeting 映射为 store.getters.welcomeMessage }) } }; </script>
|
注释说明:
calcDouble: 'doubledCount' 将组件的 calcDouble 计算属性映射到 store 的 doubledCount getter。
🧬 mapMutations
mapMutations 辅助函数用于将 store 中的 mutations 映射到组件的 methods 中。这样你就可以在组件方法中直接调用 this.mutationName(payload) 来提交 mutation,而不是使用 this.$store.commit('mutationName', payload)。
🧩 不用 mapMutations
不使用 mapMutations 时,你需要为每个 mutation 手动创建方法来调用 this.$store.commit。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <p>Count: {{ $store.state.count }}</p> <button @click="incrementCountManually">Increment Count Manually</button> <button @click="setMessageManually('New Manual Message')">Set Message Manually</button> </div> </template>
<script> export default { methods: { // 手动定义方法来提交 mutation incrementCountManually() { this.$store.commit('INCREMENT_COUNT', 5); // 手动调用 $store.commit }, setMessageManually(newMessage) { this.$store.commit('SET_MESSAGE', newMessage); // 手动调用 $store.commit } } }; </script>
|
注释说明:
incrementCountManually 方法通过 this.$store.commit('INCREMENT_COUNT', 5) 来提交 INCREMENT_COUNT mutation,并传递 payload 5。
setMessageManually 方法提交 SET_MESSAGE mutation,并传递新的消息字符串。
✅ 用了 mapMutations
使用 mapMutations 可以将 mutations 映射为组件的 methods。
1. 传递字符串数组:
当映射的方法名与 mutation 名相同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <p>Count: {{ $store.state.count }}</p> <p>Message: {{ $store.state.message }}</p> <button @click="INCREMENT_COUNT(2)">Increment Count</button> <button @click="SET_MESSAGE('Hello from mapMutations!')">Set Message</button> </div> </template>
<script> import { mapMutations } from 'vuex';
export default { methods: { // 使用 mapMutations 辅助函数将 store 中的 mutations 映射到局部方法 ...mapMutations([ 'INCREMENT_COUNT', // 映射 this.INCREMENT_COUNT() 为 this.$store.commit('INCREMENT_COUNT') 'SET_MESSAGE' // 映射 this.SET_MESSAGE() 为 this.$store.commit('SET_MESSAGE') ]) // 调用 this.INCREMENT_COUNT(payload) 等同于 this.$store.commit('INCREMENT_COUNT', payload) } }; </script>
|
注释说明:
mapMutations(['INCREMENT_COUNT', 'SET_MESSAGE']) 会将 INCREMENT_COUNT 和 SET_MESSAGE mutations 映射为组件的同名方法。
- 调用
this.INCREMENT_COUNT(2) 时,2 会作为 payload 传递给 INCREMENT_COUNT mutation。
2. 传递对象:
当映射的方法名与 mutation 名不同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <p>Count: {{ $store.state.count }}</p> <button @click="addCount(3)">Add to Count</button> <button @click="changeMessage('Message updated via alias!')">Change App Message</button> </div> </template>
<script> import { mapMutations } from 'vuex';
export default { methods: { ...mapMutations({ addCount: 'INCREMENT_COUNT', // 将 this.addCount() 映射为 this.$store.commit('INCREMENT_COUNT') changeMessage: 'SET_MESSAGE' // 将 this.changeMessage() 映射为 this.$store.commit('SET_MESSAGE') }) // 调用 this.addCount(payload) 等同于 this.$store.commit('INCREMENT_COUNT', payload) } }; </script>
|
注释说明:
addCount: 'INCREMENT_COUNT' 将组件的 addCount 方法映射到名为 INCREMENT_COUNT 的 mutation。调用 this.addCount(3) 实际上是执行 this.$store.commit('INCREMENT_COUNT', 3)。
🚀 mapActions
mapActions 辅助函数用于将 store 中的 actions 映射到组件的 methods 中。这样你就可以在组件方法中直接调用 this.actionName(payload) 来分发 action,而不是使用 this.$store.dispatch('actionName', payload)。
🧩 不用 mapActions
不使用 mapActions 时,你需要为每个 action 手动创建方法来调用 this.$store.dispatch。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <template> <div> <p>Count: {{ $store.state.count }}</p> <p>Message: {{ $store.state.message }}</p> <button @click="incrementAsyncManually">Increment Async Manually</button> <button @click="updateMsgManually('Async new message')">Update Message Async Manually</button> </div> </template>
<script> export default { methods: { // 手动定义方法来分发 action incrementAsyncManually() { // 手动调用 $store.dispatch,并传递 payload 对象 this.$store.dispatch('incrementAsync', { amount: 10, delay: 500 }); }, updateMsgManually(newMessage) { // 手动调用 $store.dispatch this.$store.dispatch('updateMessage', newMessage); } } }; </script>
|
注释说明:
incrementAsyncManually 方法通过 this.$store.dispatch 分发 incrementAsync action,并传递包含 amount 和 delay 的 payload 对象。
updateMsgManually 方法分发 updateMessage action。
✅ 用了 mapActions
使用 mapActions 可以将 actions 映射为组件的 methods。
1. 传递字符串数组:
当映射的方法名与 action 名相同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div> <p>Count: {{ $store.state.count }}</p> <p>Message: {{ $store.state.message }}</p> <button @click="incrementAsync({ amount: 3, delay: 1500 })">Increment Async</button> <button @click="updateMessage('Hello from mapActions!')">Update Message</button> </div> </template>
<script> import { mapActions } from 'vuex';
export default { methods: { // 使用 mapActions 辅助函数将 store 中的 actions 映射到局部方法 ...mapActions([ 'incrementAsync', // 映射 this.incrementAsync() 为 this.$store.dispatch('incrementAsync') 'updateMessage' // 映射 this.updateMessage() 为 this.$store.dispatch('updateMessage') ]) // 调用 this.incrementAsync(payload) 等同于 this.$store.dispatch('incrementAsync', payload) } }; </script>
|
注释说明:
mapActions(['incrementAsync', 'updateMessage']) 将 incrementAsync 和 updateMessage actions 映射为组件的同名方法。
- 调用
this.incrementAsync({ amount: 3, delay: 1500 }) 时,该对象会作为 payload 传递给 incrementAsync action。
2. 传递对象:
当映射的方法名与 action 名不同时。
代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <p>Count: {{ $store.state.count }}</p> <button @click="addAsync({ amount: 7 })">Add to Count Async</button> <button @click="modifyMessage('Asynchronously changed message!')">Modify App Message Async</button> </div> </template>
<script> import { mapActions } from 'vuex';
export default { methods: { ...mapActions({ addAsync: 'incrementAsync', // 将 this.addAsync() 映射为 this.$store.dispatch('incrementAsync') modifyMessage: 'updateMessage' // 将 this.modifyMessage() 映射为 this.$store.dispatch('updateMessage') }) // 调用 this.addAsync(payload) 等同于 this.$store.dispatch('incrementAsync', payload) } }; </script>
|
注释说明:
addAsync: 'incrementAsync' 将组件的 addAsync 方法映射到名为 incrementAsync 的 action。调用 this.addAsync({ amount: 7 }) 实际上是执行 this.$store.dispatch('incrementAsync', { amount: 7 })。
总结一下,Vuex 的辅助函数 (mapState, mapGetters, mapActions, mapMutations) 大大简化了在 Vue 组件中与 store 的交互,使得代码更加简洁、易读和易于维护。它们通过将 store 的属性和方法直接映射到组件的 computed 和 methods 中,减少了模板和脚本中的冗余代码。