VueJS中如何正确使用计算属性?优化VueX状态映射的重复逻辑
重复计算属性的优化方案
你遇到的重复逻辑本质上分为两类,完全可以通过分层设计消除冗余,不需要在每个组件内重复写判断分支:
1. 拆分两类重复逻辑
- 无加工的直通映射:类似示例中的
getToken,仅做store -> 组件的取值,没有任何额外判断 - 规则统一的加工映射:类似
totalCoin、totalGem,两个属性的判断分支完全一致,仅取值的状态键名不同
2. 用Vuex原生工具消除直通映射的冗余
对于纯直通取值的计算属性,无需逐个手动写函数,直接用Vuex提供的mapState批量映射即可:
import { mapState } from 'vuex' computed: { ...mapState({ // 一行完成store值到组件计算属性的映射 getToken: state => state.userToken, userInfo: state => state.userInfo }) }
3. 抽公共逻辑工厂,消除带统一规则的加工映射冗余
对于判断逻辑完全一致的属性,不要把相同的if分支抄到每个计算属性里,只需要把通用判断逻辑封装一次,再通过工厂函数批量生成映射规则即可:
首先把通用的状态格式化逻辑抽成纯函数(全局仅写一次):
// 可放在公共工具文件或store公共文件中 const formatNullableNumber = (val) => { if (val === 0) return 0 if (val === null) return undefined return val }
再写个工厂函数,自动生成对应状态的映射规则:
const mapFormattedState = (moduleName, stateKey) => { return (state) => { const rawVal = state[moduleName][stateKey] // 直接复用全局的格式化逻辑,无重复判断 return formatNullableNumber(rawVal) } }
组件内使用时,不需要重复写判断分支,仅需传入对应的模块名、状态键名即可:
computed: { ...mapState({ totalCoin: mapFormattedState('ApiState', 'totalCoin'), totalGem: mapFormattedState('ApiState', 'totalGem'), // 后续新增同规则的状态,一行即可完成映射 totalExp: mapFormattedState('ApiState', 'totalExp') }) }
4. 更优实践:将格式化逻辑下沉到Vuex Getters层
状态的加工逻辑本身就是Vuex Getters的核心职责,完全不应该把判断分支散落在各个组件的计算属性中:
- 在Vuex定义Getters的文件中,复用之前封装的格式化函数,统一生成所有需要加工的状态:
const getters = { getToken: state => state.userToken, totalCoin: state => formatNullableNumber(state.ApiState.totalCoin), totalGem: state => formatNullableNumber(state.ApiState.totalGem), // 批量生成所有同规则的状态Getter,无需逐个手写 ...Object.fromEntries( ['totalExp', 'totalHp', 'totalMp'].map(stateKey => [ stateKey, state => formatNullableNumber(state.ApiState[stateKey]) ]) ) }
- 组件内直接通过
mapGetters引入加工完成的状态,连之前的映射函数都不需要写:
import { mapGetters } from 'vuex' computed: { ...mapGetters(['getToken', 'totalCoin', 'totalGem', 'totalExp']) }
这种写法的实际收益很直接:所有用到同一状态的组件拿到的值都经过统一规则处理,不会出现个别组件漏写判断导致的取值异常;后续如果需要调整格式化规则(比如将
null的返回值从undefined改成空字符串),仅需修改一处公共逻辑,不需要遍历所有组件的计算属性逐行修改。
内容的提问来源于stack exchange,提问作者Eugene Chua
相关产品推荐
相关产品推荐

