Vue3-10 Vuex

For Vue3

安装

yarn add vuex@next --save

创建

import {createStore} from 'vuex';

export default createStore({
  state: {
    count: 0
  },
  mutations: {
    changeCount(state, isAdd) {
      state.count = isAdd ? state.count + 1 : state.count - 1;
    }
  },
  actions: {},
  modules: {}
});


const app = createApp({ /* 根组件 */ })

// 将 store 实例作为插件安装
app.use(store)

组合式API

通过调用useStore函数,在setup中访问Store,这与在选项是API中使用this.$store是等效的

访问State和Getter

需要创建computed引用并保留响应性

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

export default {
  setup () {
    const store = useStore()

    return {
      // 在 computed 函数中访问 state
      count: computed(() => store.state.count),

      // 在 computed 函数中访问 getter
      double: computed(() => store.getters.double)
    }
  }
}

访问Mutation和Action

访问Mutation和Action,只需要在setup钩子函数中调用commitdispatch即可

import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()

    return {
      // 使用 mutation
      increment: () => store.commit('increment'),

      // 使用 action
      asyncIncrement: () => store.dispatch('asyncIncrement')
    }
  }
}
#

TypeScript支持

看了官方文档,也查了一些资料,目前(2021.05.18),使用Vue3 + Vuex4 + TypeScript的解决方案,想要获得比较完美的TypeScript支持是比较困难的,尤其是在使用了Vuex的modules的情况下,Vuex目前对TypeScript的支持实在太差了

而之前Vue2 + TypeScript + Vuex + Vuex-class的解决方案,虽然书写比较麻烦,但是好歹能够获得比较好的类型支持,但是由于Vuex-class迟迟没有支持Vue3,所以这套解决方案也是不可行的

所以目前使用Vuex4要慎重,可以等等Vuex5,Vuex5带来了很多令人兴奋的特性,比如取消了Mutation,用组合代替了Modules的嵌套等等,或者自己实现一个简单版本的Vuex5也是可行的,具体可以参考这篇文章,介绍的很详细,我很赞同

基于现在的方案,使用Vuex鼓捣出了一个勉强在组合式API中可以用的方案,但是有两个缺点:

  1. Module内部再嵌套Module的话类型判断会报错
  2. commitdispatch都无法获得类型提示

具体的看代码

简易Store

仿照上面的文章,实现了一个简易的Store,好像也能凑合着用,感觉在Vuex5出来之前,也许在业务代码中再完善一下,采用这种方案可能更优雅一点?

两个Store,不存在嵌套关系了,root-store中还是定义全局变量,types定义类型:

// types.ts
export interface RootStates {
  count: number;
}

export interface RootActions {
  changeCountAct(payload: {newVal: number}): Promise<void>;
}

index中定义Store的具体实现,借助reactive这个API,返回值是readonly防止被意外更改,Action负责更改State,也可以在里面完成异步请求(不考虑快照和调试的问题了),然后导出一个useRootStore

// root-store/index.ts
import {reactive, readonly} from 'vue';
import {RootStates, RootActions} from './types';
import {mock} from '@/utils';

const createStore = () =>
  reactive<RootStates>({
    count: 0
  });

const createAction = (state: RootStates): RootActions => ({
  async changeCountAct({newVal}) {
    state.count = await mock(newVal);
  }
});

const state = createStore();
const action = createAction(state);

export const useRootStore = () => ({
  state: readonly(state),
  dispatch: readonly(action)
});

example-store中类似,导出的useExampleStore,这两个Store在外层的index中组装,并且可以相互调用

// index.ts
import {useRootStore} from './root-store';
import {useExampleStore} from './exmaple-store';

const allStore = {
  root: useRootStore(),
  example: useExampleStore()
};

export const useStore = (storeName: keyof typeof allStore = 'root') => allStore[storeName];

在组件中调用root-store时,可以获得类型提示和校验:

import {useStore} from '@/data';

export default defineComponent({
  name: 'Vuex',
  setup() {
    const store = useStore();

    const rootCount = computed(() => store.state.count);

    const changeRootCount = (isAdd: boolean) => {
      const newVal = isAdd ? store.state.count + 2 : store.state.count - 2;
      store.dispatch.changeCountAct({newVal});
    };

    return {rootCount, changeRootCount};
  }
});

同样调用example-store时,为useStore传入example字符串即可,全部代码在这里

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值