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
中,减少了模板和脚本中的冗余代码。