Vue3 vuex的辅助函数

1,432 阅读1分钟
  • 前言

在项目开发中,经常会用到vuex来对数据进行管理,随后数据增多,会使用语法糖来帮助快速开发。即vuex中的mapStatemapGettersmapMutationsmapActions等辅助函数是在项目中常用到的。

  • 辅助函数的使用

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。更别说mapGettersmapMutationsmapActions,所以得到一个事实:辅助函数就是会返回一个对象。
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
            }
    }