Vue2里的mapState是干啥的?怎么用才顺手?
想搞懂Vue2里的mapState咋回事?这东西在Vuex状态管理里挺常用,能帮咱们更简洁地处理组件里的状态映射,今天就从“是啥”“咋用”“有啥坑”这些角度唠明白,新手也能跟着学会~
mapState到底是个啥?
咱先把Vuex和state的关系理清楚:Vuex是Vue的状态管理库,state就是存全局数据的“仓库”,比如用户信息、购物车商品数量这些,全项目通用的数据,都存在state里。
那mapState呢?它是Vuex提供的「辅助函数」,作用特别直接——把Vuex里的state数据,映射到当前组件的计算属性里,举个大白话例子:原本你得在组件里写 computed: { userInfo() { return this.$store.state.userInfo } }
才能拿到state里的用户信息,现在用mapState,一行代码就能搞定多个state的映射,不用重复写this.$store.state.xxx
这种模板代码,效率直接拉满!
啥场景下非得用mapState?
不是所有情况都得用mapState,但碰到这两类场景,用它能省老多事儿:
-
组件需要多个state数据:比如一个页面要同时显示「用户昵称」「购物车商品数」「主题颜色」这三个存在state里的信息,要是不用mapState,得写三个计算属性,每个都重复
this.$store.state.xxx
;用mapState的话,一行数组写法就能把这三个全映射过来。 -
追求代码简洁性:Vuex的核心思想是“单一状态树”,但实际项目里state可能很臃肿,mapState能帮你把和当前组件无关的state过滤掉,只映射需要的,代码看起来更清爽,后期维护也方便。
mapState基础用法咋上手?
学会这三种写法,基本能覆盖90%的场景:
数组形式(最简单直接)
先从Vuex里导入mapState,然后在组件的computed
里用数组列出来要映射的state名称,举个完整例子:
<template> <div> <!-- 直接用映射后的计算属性 --> <p>用户昵称:{{ userInfo.name }}</p> <p>购物车数量:{{ cartCount }}</p> </div> </template> <script> import { mapState } from 'vuex' // 先导入 export default { name: 'MyComponent', computed: mapState(['userInfo', 'cartCount']) // 数组里写state的key } </script>
这种写法的前提是:组件里的计算属性名,和Vuex state里的key完全一样,比如state里有个叫userInfo
的对象,组件里计算属性也叫userInfo
,这样映射后直接用就行。
对象形式(解决命名冲突)
要是组件自身的data、props,或者其他计算属性,和state的key重名了咋办?这时候用对象形式,给映射后的计算属性改个新名字,比如state里有个userInfo
,但组件里已经有个叫user
的变量了,就可以这样写:
computed: mapState({ // 新名字: 'state里的key' userData: 'userInfo', cartNum: 'cartCount' })
这样组件里用{{ userData.name }}
、{{ cartNum }}
就能拿到对应数据,避免命名冲突。
函数形式(需要自定义逻辑)
有时候映射state时,得结合组件自身的属性,或者对state数据做简单处理,这时候用「函数形式」,参数是Vuex的state,还能拿到组件的this
(注意别用箭头函数,否则this指向不对),比如state里存的是用户年龄,组件里要显示“用户年龄:xxx岁”:
computed: mapState({ userAgeWithUnit(state) { // state是Vuex的state对象,this是当前组件实例 return `用户年龄:${state.userAge}岁` } })
结合自定义计算属性(灵活混用)
实际开发中,组件里可能既有从state映射来的计算属性,又有自己的业务逻辑计算属性,这时候用「对象展开符(...)」把mapState和自定义计算属性合并:
computed: { ...mapState(['userInfo', 'cartCount']), // 先映射state // 自己的计算属性 isCartEmpty() { return this.cartCount === 0 } }
这样组件里既能用userInfo
这些state数据,又能调用isCartEmpty
判断购物车是否为空,灵活度拉满~
用mapState容易踩的坑有哪些?
别觉得学会用法就万事大吉了,这些“小陷阱”稍不注意就栽跟头:
-
忘记放在computed里:mapState本质是生成计算属性,所以必须写在
computed
选项里!要是错放到methods
里,不仅拿不到响应式数据,页面还不更新,debug时能把人急死。 -
命名冲突埋雷:前面说过用对象形式解决,但要是没注意,组件的data、props和mapState映射的名字重复,后定义的会把先定义的覆盖,比如组件data里有个
userInfo
,mapState又映射了userInfo
,那最终计算属性里的userInfo
会变成state里的值,把data里的覆盖掉,逻辑直接乱套。 -
箭头函数搞丢this:用函数形式写mapState时,要是写成箭头函数
userAge: (state) => state.userAge + this.name
,这里的this
就不是组件实例了(箭头函数没有自己的this,会向上找作用域),所以必须用普通函数写法,让this
指向组件:userAge(state) { return state.userAge + this.name }
。
mapState和其他Vuex辅助函数咋配合?
Vuex里还有mapGetters(映射getters)、mapActions(映射actions)这些辅助函数,和mapState配合起来用,能让组件逻辑更丝滑:
- 和mapGetters一起用:getters是state的“派生状态”(比如购物车商品总价,需要根据cartList计算),把mapState和mapGetters都放computed里:
computed: { ...mapState(['cartList']), ...mapGetters(['cartTotalPrice']) }
组件里既能拿到原始的购物车列表(cartList),又能直接用getters计算好的总价(cartTotalPrice)。
- 和mapActions一起用:actions是处理异步操作的,虽然mapActions要放在
methods
里,但思路一样——简化this.$store.dispatch('xxx')
的写法。
methods: { ...mapActions(['addToCart']), // 映射actions里的addToCart方法 handleAdd() { this.addToCart({ productId: 123 }) // 直接调用,不用写this.$store.dispatch } }
模块(Module)里的mapState咋用?
实际项目中,Vuex的state会按功能拆成多个模块(比如user模块、cart模块),这时候用mapState得注意命名空间(namespace):
假设我们有个cart模块,state里有cartCount,并且开启了命名空间:
// store/modules/cart.js export default { namespaced: true, // 开启命名空间 state: { cartCount: 3 }, // ...其他配置 }
这时候映射cart模块的state,得给mapState传两个参数:模块名和要映射的state数组/对象:
computed: { ...mapState('cart', ['cartCount']), // 第一个参数是模块名 // 或者对象形式 ...mapState('cart', { cartNum: 'cartCount' }) }
这样就能精准拿到某个模块下的state,避免不同模块间的state重名冲突~
mapState是Vue2 + Vuex开发里简化状态映射的神器,核心就是“少写重复代码,让组件更专注业务”,只要记住「辅助函数的本质是生成计算属性」「三种写法应对不同场景」「避开命名和this的坑」,再结合模块和其他辅助函数,状态管理这块儿就稳了~要是你刚开始学Vuex,建议把项目里的小功能(比如购物车、用户信息)用mapState练手,写着写着就熟练啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。