-
前言
在项目开发中,经常会用到vuex来对数据进行管理,随后数据增多,会使用语法糖来帮助快速开发。即vuex中的mapState、mapGetters、mapMutations和mapActions等辅助函数是在项目中常用到的。
-
辅助函数的使用
Vue2中,options API在computed中使用mapSate
computed:mapsState(['name','age'])
Vue3里主要是使用setup来进行操作,vuex来进行数据操作,通过useStore钩子得到
import { useStore } from 'vuex'
import { computed } from 'vue'
setup(){
const store = useStore()
const name = computed( ()=> store.state.name )
const age = computed( () => store.state.age )
return {
name,age
}
}
缺点是随着数据增多,显得很冗长,所以用到辅助函数mapState来解决。但Vue3官方文档并没着重的解释如何使用mapState. Vue2:
setup(){
const stateStore = mapState(['name','age'])
return{
...stateStore
}
}
使用后发现,返回的结果是个函数?!
- 为什么在setup中使用mapState会返回函数?
通过操作mapState的源码,发现是通过
this.$store来得到store的值,但在setup中是拿不到this。更别说mapGetters、mapMutations、mapActions,所以得到一个事实:辅助函数就是会返回一个对象。
computed:{
...mapstate(['name','age'])
}
// 转换为
{
name:function(){},
age:function(){}
}
综上所述,所以用vue2的写法在setup为什么中会返回一个函数啦!
- 封装一个useState函数
这样我们可以使用computed来奥做mapState,
因为cpmputed本身是个函数,会接受一个函数作为参数。而辅助函数是被解析成一个对象,对象中的属性值是函数。
所以可以将两者结合封装一个hooks来使用
import { useStore,mapState } from 'vuex'
import { computed } from 'vue'
const useState = function(mapper){
// mapper: Array / object
const store = userStore()
// 使用辅助函数解析成一个对象
const storeStateFns = mapState(mapper)
const stareState = {}
// 通过object.keys拿到对象的所有key值,遍历,取出对应的value值,就是函数
object.keys(storeStateFns).forEach(item => {
//辅助函数的内部是通过this.$store实现
//setup中没有this, 通过bind来改变this的只想
const fn = storeStateFns[item].bind({$store:store});
//拿到函数,作为计算属性看的参数,最后一个保留在对象中
storeState[item] = computed(fn)
})
// storeState是一个对象,key是字符串,value值是ref对象
return storeState
}
export defalut useState
组件中这样使用
setup(){
const stateStore = useState(['name','age'])
return{
...stateStore
}
}
- 封装一个useMapper函数 [mapGetters]也是根据相同的思路来封装。
import { computed } from 'vuex'
import { mapGetters, mapState, useStore } from 'vuex'
const useMapper = (mapper,mapFn) => {
const store = useStore()
const storeStateFns = mapFn(mapper)
const storeState = {}
object.key(storeStateFns).forEach((keyFn) => {
const Fn = storeStateFns[keyFn].bind({$store:store})
stroeState[keyFn] = computed(fn)
})
return storeState
}
export const useState = (mapper) =>{
return useMapper(mapper,mapState)
}
export const useGetters = (mapper) => {
return useMapper(mapper,mapGetters)
}
使用情况
setup(){
const storeState = useState(mapper:['name','age','six'])
const storeGetters(mapper:['counter'])
return{
...storeState,
...storeGetters,
}
}
[mapMutatios、mapActions】是不用进行封装的,因为这两个本身就是调用方法的
- 关于模块化的考虑
import { computed } from 'vue'
import { mapGetters, mapState, useStore, createNamespacedHelpers } from 'vuex'
const useMapper = (mapper, mapFn) => {
const store = useStore()
const storeStateFns = mapFn(mapper)
const storeState = {}
Object.keys(storeStateFns).forEach((keyFn) => {
const fn = storeStateFns[keyFn].bind({ $store: store })
storeState[keyFn] = computed(fn)
})
return storeState
}
export const useState = (moduleName, mapper) => {
let mapperFn = mapState
if (typeof moduleName === 'string' && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapState
} else {
mapper = moduleName
}
return useMapper(mapper, mapperFn)
}
export const useGetters = (moduleName, mapper) => {
let mapperFn = mapGetters
if (typeof moduleName === 'string' && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapGetters
} else {
mapper = moduleName
}
return useMapper(mapper, mapperFn)
}
使用
setup(){
const storeState = useState(['name','age','six'])
const storeGetters = useGetters(['counter'])
const homeState = useState('home',['homeCounter'])
return{
...streoState,
...storeGetters,
...homeState
}
}