封装vuex中modules的辅助函数

106 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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,我们会发现,页面展示的是一个函数

函数展示.png

想要转换成我们想要的数据,需要用到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

homeCounter.png

现在我们要把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函数

测试

正常展示.png 页面是可以正常展示的

源码

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老师的课程