vuex中的辅助函数在vue2.0和vue3.0的分别使用

原文链接:https://blog.csdn.net/James_xyf/article/details/118636622

前言
​ 最近自己一直在学习vue3,学习到了很多的新知识,非常的感谢coderwhy老师的指导。由于自己一直有做笔记这个习惯,学习到了vuex中的辅助函数,分别在vue2和vue3中的分别使用,以前感觉自己有必要记录下来,来对自己加深印象,巩固基础。

正题
1 、为什么要使用辅助函数
const store = new Vuex.Store({
    state: {
        name: 'james',
        age: 35,
        height: 2.03
        team: 'lakers'
    }
})
1
2
3
4
5
6
7
8
在上面创建store过程中,我们在state中,保存四个的数据,那么,我们在组件中的使用呢?

方式一:

<template>
    <div>    
        <h1>姓名:{{$store.state.name}}</h1>
        <h1>年龄:{{$store.state.age}}</h1>
        <h1>身高:{{$store.state.height}}</h1>
        <h1>团队:{{$store.state.team}}</h1>
    </div>    
</template>
1
2
3
4
5
6
7
8
​ 是不是感觉方式一,在{{}}写了太多太长的表达式了,而且这里还只有四个数据,如果数据多了,就感觉很麻烦了吧

方式二:

//采用计算属性
export default {
     computed: {
        name() {
            return this.$store.state.name
        },
        age() {
            return this.$store.state.age
        },
        height() {
            return this.$store.state.height
        },
        team() {
            return this.$store.state.team
        }
    }   

 
然后在模板中的使用

<template>
    <div>    
        <h1>姓名:{{name}}</h1>
        <h1>年龄:{{age}}</h1>
        <h1>身高:{{height}}</h1>
        <h1>团队:{{team}}</h1>
    </div>    
</template>
 
在模板中确实简便了不少,但是在计算属性中,还是需要写着很多的表达式,如果store中的数据多了,并且还在组件内部的计算属性,那么computed计算属性就非常的多(这也许就是vue2中options API的不足)。

​ vuex中的actions, mutations,getters都存在一样的现象, 所以针对上面的现象,vuex中推出了辅助函数,来方便我们解决此类的问题。

2、辅助函数的本质
vuex中提供了四个辅助函数mapState, mapMutations, mapGetters, mapActions

他们内部的源码都是通过 this.$store 来拿到store中的值的。

自己试着读一下,mapState的源码

//normalizeNamespace 是一个初始化命名空间的函数,也是返回一个函数
var mapState = normalizeNamespace(function (namespace, states) {
    var res = {};
    //这里判断是否是数组还是对象
    if (!isValidMap(states)) {
      console.error('[vuex] mapState: mapper parameter must be either an Array or an Object');
    }
    //normalizeMap函数就是用来处理数组或则对象(这个函数内部很简单)
    //最后返回一个集合对象 [{key: key, val: val}]
    normalizeMap(states).forEach(function (ref) {
        //获取到key和value的值
      var key = ref.key;
      var val = ref.val;
        
       //根据val,通过this.$store来到store的value值,然后保存在res对象中
      res[key] = function mappedState () {
        var state = this.$store.state;
        var getters = this.$store.getters;
        if (namespace) {
          var module = getModuleByNamespace(this.$store, 'mapState', namespace);
          if (!module) {
            return
          }
          state = module.context.state;
          getters = module.context.getters;
        }
        return typeof val === 'function'
          ? val.call(this, state, getters)
          : state[val]
      };
      // mark vuex getter for devtools
      res[key].vuex = true;
    });
    //最后包对象返回
    return res
  });
 
其他的辅助函数,是返回同样的数据结构,所以是一样处理的。

阅读上面的源码,我们很清楚的知道,辅助函数就返回的一个对象,对象的形式就是 key是字符串,value就是函数,大致的形式如下:

computed: {
    //这里也很容易清楚,这里为什么需要结构(因为返回的是一个对象,哈哈哈,啰嗦了)
    ...mapState(['name', 'age'])
}

//转化的形式如下
{
    name: function() {},
    age: function() {}
}
 
上面说了这么多,其实总结出来就两句话:

辅助函数返回一个对象,对象的形式是 key是字符串, value是函数

内部是实现使用this.$store来得到store中的值 (这里主要是在vue3中的setup时,要注意,setup中没有this)

3、辅助函数在vue2中的使用
辅助函数,就两种形式的写法,对象形式和数组形式

3.1 mapState
mapState一般在计算属性中使用

...mapState(['name', 'age'])    //数组形式
...mapState({                   //对象的形式
    name: state => state.name,
    age: state => state.age
})
 
3.2 mapGetters
mapGetters也是一般在计算属性中使用

...mapState(['translateName', 'translateAge'])    //数组形式
...mapState({                                     //对象的形式
    translateName: 'translateName',
    translateAge: 'translateAge'
})
 
3.3 mapMutations 和 mapActions
他们的使用方法和mapGettets的方式一样的,只不过在他们是在methods中使用

...mapMutations(['changeName', 'changeAge'])       //数组形式
...mapMutations({                                  //对象的形式
    changeName: 'changeName',
    changeAge: 'changeAge'
})

...mapActions(['asyncChangeName', 'asyncChangeAge'])       //数组形式
...mapActions({                                  //对象的形式
    changeName: 'asyncChangeName',
    changeAge: 'asyncChangeAge'
})
 
4、辅助函数在vue3中的使用
vue3中主要是使用setup函数来编写逻辑的,但是在setup中又没有this,所以我们不能通过this.$store来获取store,那么在vuex4中, 提供了一个钩子函数useStore

import { useStore } from 'vuex'
const store = useStore()
 
所以在setup中使用store,那么就变得简单了

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
    }
}
 
是不是,写的很难受啊。是不是又回到最开始的疑问啦? 当数据变多的时候, 又会大大的增加代码量。所以,我们还是需要借助辅助函数。

4.1 mapState
在vue3的官网中,没有明确的提示到使用辅助函数,但是我们可以通过自己的分析,来使用辅助函数

我们知道计算属性computed是一个函数,接受一个函数作为参数, 我们还知道 辅助函数最后 被解析成一个对象,对象中的属性值也是函数,那我们怎么考虑结合起来呢?

是不是只要把对象中的属性值作为computed的参数就可以了。

使用辅助函数,封装一个useState的hooks函数

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

//mapper: Array | Object
const useState = function(mapper) {
    const store = useStore()
    
    //使用复制函数解析成一个对象
    const storeStateObj = mapState(mapper)
    const res = {}
    
    //通过Object.keys拿到对象的所有key值,遍历,取出对应的value值,也就是函数
    Object.keys(storeStateObj).forEach(item => {
        //这我们知道辅助函数的内部是通过this.$store来实现的
        //setup中没有this, 所以通过bind来改变this的指向
        const fn = storeStateObj[item].bind({$store, store})
        //拿到函数,作为计算属性的参数,最后在留在一个对象中
        res[item] = computed(fn)
    })
    
    //res是一个对象, key是字符串, value值是ref对象
    return res
}

export default useState
 
在组件中使用

import useState from './hooks/useState'

export default {
    setup() {
        const storeObj = useState(['name', 'age'])
        //当然对象也行
        return {
            ...storeObj
        }
}
 
是不是又可以愉快的写代码啦!

4.2 mapGetters
mapState 和 mapGetters的使用方式, 基本一样,也都是在computed计算属性中使用。

使用辅助函数, 封装一个useGetters的hooks函数

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

//mapper: Array | Object
const useGetters = function(mapper) {
    const store = useStore()
    
    //使用复制函数解析成一个对象
    const storeStateObj = mapGetters(mapper)
    const res = {}
    
    //通过Object.keys拿到对象的所有key值,遍历,取出对应的value值,也就是函数
    Object.keys(storeStateObj).forEach(item => {
        //这我们知道辅助函数的内部是通过this.$store来实现的
        //setup中没有this, 所以通过bind来改变this的指向
        const fn = storeStateObj[item].bind({$store, store})
        //拿到函数,作为计算属性的参数,最后在留在一个对象中
        res[item] = computed(fn)
    })
    
    //res是一个对象, key是字符串, value值是ref对象
    return res
}

export default useGetters
 
跟上面的useState基本是一样的。

4.3 useState和useGetters的高度封装
//common.js

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

const commonFn = function(mapper, mapFn) {
    const store = useStore()
    const storeStateObj = mapFn(mapper)
    const res = {}
    Object.keys(storeStateObj).forEach(item => {
        const fn = storeStateObj[item].bind({$store, store})
        res[item] = computed(fn)
    })
    return res
}

export default commonFn
 
//useState.js
import { mapState } from 'vuex'
import commonFn from './common.js'

const useState = (mapper) => {
    return commonFn(mapper, mapState)
}
export default useState
1
 
//useGetters.js
import { mapGetters } from 'vuex'
import commonFn from './common.js'

const useGetters = (mapper) => {
    return commonFn(mapper, mapGetters)
}
export default useGetters
 
4.4 mapMutations 和 mapActions
mutaiton本来就是一个方法,所以直接跟辅助函数的属性值挂钩,

import { mapMutations, mapActions } from 'vuex'

export default {
    setup() {
        //mutations
        const mutationsObj = mapMutations(['changeName', 'changeAge'])
        
        //等价于
        const mutationsObj = mapMutations({
            changeName: 'changeName',
            changeAge: 'changeAge'
        })
        
        //action
        const actionsObj = mapMutations(['asyncChangeName', 'anyncChangeAge'])
        
        //等价于
        const actionsObj = mapMutations({
            changeName: 'asyncChangeName',
            changeAge: 'anyncChangeAge'
        })
        
        return {
            ...mutationsObj
        }
    }
}
 
5、补充
在上面,我们辅助函数封装了useState, useGetters两个函数,来处理store中的值,但是呢?现在补充考虑不周到的是: 没有考虑到模块的情况,所以重新封装了一下。

//common.js

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

const commonFn = function(mapper, mapFn) {
    const store = useStore()
    const storeStateObj = mapFn(mapper)
    const res = {}
    Object.keys(storeStateObj).forEach(item => {
        const fn = storeStateObj[item].bind({$store, store})
        res[item] = computed(fn)
    })
    return res
}

export default commonFn
 
这里的common.js没有改变

借助vuex提供的createNamespacedHelpers函数来得到模块中的属性

//useState.js
import { mapState, createNamespacedHelpers } from 'vuex'
import commonFn from './common.js'

//第一个参数为模块的名称,为了在模块中,也可以使用辅助函数
const useState = (moduleName, mapper) => {
    let mapperFn = mapState
    if(typeof moduleName === 'string' && moduleName.length > 0) {
        //防止出现useState('', [])发生了
        mapperFn = createNamespacedHelpers(moduleName).mapState
    } else {
        mapper = moduleName
    }
    return commonFn(mapper, mapperFn)
}
export default useState
 
//useGetters .js
import { mapGetters, createNamespacedHelpers } from 'vuex'
import commonFn from './common.js'

//第一个参数为模块的名称,为了在模块中,也可以使用辅助函数
const useGetters = (moduleName, mapper) => {
    let mapperFn = mapGetters
    if(typeof moduleName === 'string' && moduleName.length > 0) {
        //防止出现useState('', [])发生了
        mapperFn = createNamespacedHelpers(moduleName).mapGetters
    } else {
        mapper = moduleName
    }
    return commonFn(mapper, mapperFn)
}
export default useGetters 
 
createNamespacedHelpers的源码

 var createNamespacedHelpers = function (namespace) { return ({
    mapState: mapState.bind(null, namespace),
    mapGetters: mapGetters.bind(null, namespace),
    mapMutations: mapMutations.bind(null, namespace),
    mapActions: mapActions.bind(null, namespace)
  }); };
 
 
结语
​ 辅助函数为我们使用vuex提供了很多的方便,但是在vue2和vue3中的使用方式有点差别,其实也还好吧。不很难,多熟悉几遍就好了。

​ 如果上面有不对的地方,请喷,我虚心接受
————————————————
版权声明:本文为CSDN博主「copyer_xyf」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/James_xyf/article/details/118636622

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue 3.0是Vue.js框架的最新版本,与Vue 2.0相比有一些重要的改进和变化。要将Vue 2.0项目迁移到Vue 3.0,需要进行以下步骤: 1. 更新依赖项:首先,需要将项目Vue.js依赖项更新为最新的3.0版本。这包括Vue核心库以及其他可能使用Vue插件或扩展。 2. 代码适配:Vue 3.0引入了一些新的语法和API,与Vue 2.0有一些不兼容的变化。因此,需要对项目的代码进行适配。例如,Vue 3.0使用了新的Composition API,可以取代2.0版本的Options API,需要对组件进行适配以使用新的API。另外,一些特性,如slot和transition,也有一些变化,需要根据Vue 3.0的文档进行修改。 3. 构建工具更新:Vue 3.0对应的构建工具也有所改变。如果你的项目使用Vue CLI或其他构建工具,需要将它们更新为最新的版本以支持Vue 3.0。 4. 运行测试:完成代码适配后,需要进行测试以确保项目在Vue 3.0下能够正常运行。可以使用Vue官方提供的测试工具或其他适用的测试框架进行测试。 5. 性能优化:Vue 3.0在性能方面进行了一些改进,因此可以考虑对项目进行性能优化。这包括使用新的编译优化、按需引入和缓存等。 总之,迁移到Vue 3.0需要更新依赖项、适配代码、更新构建工具、进行测试和性能优化等步骤。通过认真阅读Vue 3.0的文档和指南,并根据项目的具体情况进行相应的修改和调整,可以顺利完成迁移过程。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值