分享一个Vuex的使用的新姿势

本文适合对Vuex有过中度使用--至少在一个项目使用vuex以及相关辅助函数的朋友阅读.
  • 关于Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。以上就是官网的解释,简单来说,就是简化为了高阶组件传参,统一管理各个组件都需要共享的一个数据状态,如果组件间不是父子组件,那么传参起来可能就很麻烦,当然通过其他手段也能实现,但目前来说都比较繁琐,这时候,就需要用到我们的数据状态管理了。
  • 数据更改流程
我就直接放官网一张图说明好了:

意思就是我们把需要管理的数据放在 state 中,从 state 中取出数据渲染到页面中,然后用户在页面层发起更改数据,数据更改要通过mutation 去改,异步操作还需要用 actions 去触发 mutation,整个过程如下图:

说到这里,差不多就介绍完概念了,下面我们看它的使用新姿势。

因为是给已经有 vuex 使用经验的小伙伴分享,我就直接上代码了。

最基本的打开方式是这样的

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

用辅助函数更改数据是这样的

import { mapMutations } from 'vuex'
export default {
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}
以上不论哪种方式,他们需要这样——写一堆 mutation
export const mutations = {
  changeIsPhone(state, isPhone) {
    state.isPhone = isPhone;
  },
  changeMenuIndex(state, menuIndex) {
    state.menuIndex = menuIndex;
  },
  changeTabbarShow(state, show) {
    state.tabbarShow = show;
  },
  changTopbarShow(state, show) {
    state.topbarShow = show;
  },
  setPaintingInfo(state, paintingInfo) {
    state.paintingInfo = paintingInfo;
  },
  setArticleCategory(state, category) {
    state.articleCategory = category;
  },
  changeUser(state, user) {
    state.user = user;
  },
  changeIsLogin(state, isLogin) {
    state.isLogin = isLogin;
  },
  changeLoginDialogShow(state, show) {
    state.loginDialogShow = show;
  },
  changeLoginDialogType(state, type) {
    state.loginDialogType = type;
  }
};
经过经验累积可发现,我们的 mutation大多数都只是做简单的数据更新,如果其中有复杂的逻辑变化,一般都是交给 actions 去做了,我们可以在 actions 里面做异步请求,数据处理,最后将处理好的数据通过 mutation 更改,那既然 mutation 形为这么一致,我们为什么不把他封装起来了呢?
说做就做。
我们先给他封装 store 对象封装一个魔法方法,主要看__s这个魔法方法。
export type MagicMethod = {
  // 触发 mutation
  __s?: (type: string, msg: string) => any;
  // 触发 actions
  __d?: (type: string, msg: string) => any;
  // 触发 getter
  __g?: (type: string, msg: string) => any;
  commit: Commit;
  dispatch: Dispatch;
  getters: any;
}

const store: Store<any> & MagicMethod= = new Vuex.Store({
  strict: true,
  state,
  mutations,
  actions,
  getters,
  modules,
  plugins: [
    // 持久化插件
    VuexPersistedState({
      paths: ['app.language']
    })
  ]
})

// 这是重点!重点!重点!
@param type - 需要更改的数据名,模块名以.分隔,如 user 模块下的info 属性,type 应为 user.info
store.__s = (type, msg) => {
  let _state = store.state
  if (!type) return store.state
  // 判断是根 state 还是 module 下的
  if (type.indexOf('.') === -1) {
    if (msg !== undefined) {
      store.commit({
        type: '__set',
        key: type,
        val: msg,
        root: true
      })
      return _state
    } else {
      return _state[type]
    }
  }
  const _path = type.split('.')
  for (let i = 0; i < _path.length; i++) {
    if (_state[_path[i]] !== undefined) {
      _state = _state[_path[i]]
    } else {
      _state = undefined
    }
  }
  if (msg !== undefined && _path.length === 2) {
    store.commit({
      type: _path[0] + '/__set',
      key: _path[1],
      val: msg
    })
  }
  return _state
}

我们的 mutation 文件,一个方法就够了,通过 key 和 value 去更改 数据,mutation.js内容如下。

export default {
  __set(state, msg) {
    state[msg.key] = msg.val
  }
}

然后在任何一个页面,我们都不用引入 mapMutaion,mapActions 这些辅助函数,更改state 直接使用如下方式

 confirm() {
      // 更改根 state 下的 coinType属性
      this.$store.__s('coinType', this.d_selectType)
       // 更改根 state 下的 coinInfo属性
      this.$store.__s('coinInfo', coinbook[coinName])
      if (Reflect.has(coinbook[coinName].bip, '49')) {
       // 更改根 state 下的 coinProtocol属性
        this.$store.__s('coinProtocol', 49)
      } else {
       // 更改根 state 下的 coinProtocol属性
        this.$store.__s('coinProtocol', 44)
      }
       // 更改dialog 模块下的 chooseType属性
      this.$store.__s('dialog.chooseType', false)
       // 更改usb 模块下的 xpub 属性
      this.$store.__s('usb.xpub', '')
}

读取的话还是和原来一样,使用 compute读取

computed: {
  addressType:(vm) => vm.$store.__s('addressType'),
  coinProtocol: (vm) => vm.$store.__s('coinProtocol')
}

当然如果你嫌弃这样麻烦,还是可以和原来的辅助函数共存的,没有一点侵入性。
如果你也觉得这个方法有用,赶快学起来吧。
经实验证明,有大量 mutation 的情况下,真的能节约不少时间呢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值