持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情
前言
昨天我们说了在根store中封装mapGetters和mapState,如果没看的小伙伴请点击这。
这是我们分享的前置知识,如果一个项目很大,数据都在store中,会显得很复杂,vuex推出了modules,可以把不同的业务逻辑和数据放在不同的模块中,这样会显得更容易阅读,和修改
分析
我们把store分成了多个模块,但是此时我们的map函数只能使用在根store中,想对模块使用map函数,就需要用到vuex提供的createNamespacedHelpers Api,同样会出现一个问题,当我们在setup中使用createNamespacedHelpers Api生成的辅助函数,还是得使用computed函数,不然返回的是一个函数,先测试一下
store模块
const homeModule = {
namespaced:true,
state(){
return {
homeCounter:100
}
},
mutations:{
increment(state){
state.homeCounter++
}
},
actions:{
incrementActions({commit}){
commit("increment")
commit("increment",null,{root:true})
}
}
}
App模块
const { mapActions,mapState } = createNamespacedHelpers("homeModule")
export default {
setup() {
const homeActions = mapActions(["incrementActions"])
const homeState = mapState(["homeCounter"])
return {
...homeState,
...homeActions
}
}
}
我们从createNamespacedHelpers导出mapState和mapActions函数,然后在界面使用homeCounter,我们会发现,页面展示的是一个函数
想要转换成我们想要的数据,需要用到computed函数
setup() {
const store = useStore()
const homeActions = mapActions(["incrementActions"])
const homeState = mapState(["homeCounter"])
const computedHomeCounter = computed(homeState.homeCounter.bind({$store:store}))
return {
computedHomeCounter,
...homeState,
...homeActions
}
}
这样页面就会展示homeCounter
现在我们要把computed+computedHomeCounter这两个封装到之前那个hook中,并且让他们可以像Actions那样直接调用,不需要手动添加计算属性
实现
import { createNamespacedHelpers,mapState } from "vuex"
import {useMapper} from "./useMapper"
export function useState(moduleType,mapper){
let mapperFn = mapState
if(typeof moduleType === "string" && moduleType.length>0){
mapperFn = createNamespacedHelpers(moduleType).mapState
return useMapper(mapper,mapperFn)
}else{
return useMapper(mapper,mapperFn)
}
}
我们之前写过useMapper的hook,Mapper函数只需要mapper和mapperFn,mapper是传来需要加工的数据,mapperFn是vuex的map函数,我们只要对mapperFn进行修改就行,可以根据我们传来的moduleType来确定需要的map函数
测试
页面是可以正常展示的
源码
useMapper
import { useStore } from "vuex"
import { computed } from "vue"
export function useMapper(mapper,mapFn){
const store = useStore()
const storeStateFn = mapFn(mapper)
const storeState = {}
Object.keys(storeStateFn).forEach(fnKey => {
const fn = storeStateFn[fnKey].bind({$store:store})
storeState[fnKey] = computed(fn)
})
return storeState
}
useState
import { createNamespacedHelpers,mapState } from "vuex"
import {useMapper} from "./useMapper"
export function useState(moduleType,mapper){
let mapperFn = mapState
if(typeof moduleType === "string" && moduleType.length>0){
mapperFn = createNamespacedHelpers(moduleType).mapState
return useMapper(mapper,mapperFn)
}else{
return useMapper(mapper,mapperFn)
}
}
同样,如果是getter,只需要创建useGetter,把useState代码稍微一改就可以了
结束
感谢大家能看到这,谢谢,方案来自codewhy老师的课程