在Vue3中,封装一个Vuex辅助函数,useState 函数

228 阅读1分钟
graph TD
Start --> Stop

在vue2中我们可以通过 options API 在 computed 中来使用 mapState,

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 来解决。 但是呢,vuex 官方并没有例子来说明如何在setup中去使用辅助函数 mapState。 所以我就尝试着以vue2的形式来写:

setup() {
  const stateStore = mapState(['name', 'age'])
  return {
    ...stateStore
  }
},

但显示到浏览器的结果却发现是这样子的:

image.png

## 为什么在setup中使用mapState会返回函数?

通过看了一下 mapState 的源码,发现是通过 this.$store 来拿到 store 的值的 然而在 setup 中是取不到 this 的

image.png 其他的辅助函数(mapGetters、mapMutations、mapActions) 同样都是这样类似的处理的。 所以通过上面的源码,我们知道:辅助函数就是会返回一个对象,而 key 是字符串, val就是函数, 类似于:

computed:{
    ...mapState(['name','age'])
}
// 转换为了:
{ 
    name: function(){},
    age:function(){}
}

所以就明白了为什么在上述的代码中为什么会返回一个函数了。

## 封装一个 useState 函数

明白了其原理后,我们就知道了在 computed 中可以使用mapState, 是因为 computed 本身就是一个函数,它会接收一个函数作为参数。  我们也知道了辅助函数是 被解析成了一个对象,对象中的属性值是函数。

【那么我们是不是可以试着把这俩个结合起来去封装一个hooks来使用了?】

import { useStore, mapState } from 'vuex'
import { computed } from 'vue'

const useState = function(mapper) {
    // mapper: Array | Object
    const store = useStore()
    
    //使用辅助函数解析成一个对象
    const storeStateFns = mapState(mapper)
    const storeState = {}
    
    //通过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 default useState

然后在组件中就这样使用:

setup(){
    const stateStore = useState(['name','age']) // 使用对象的形式也行
    return {
        ...stateStore
    }
}