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)
通过调用useStore
函数,在setup
中访问Store,这与在选项是API中使用this.$store
是等效的
需要创建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,只需要在setup
钩子函数中调用commit
和dispatch
即可
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// 使用 mutation
increment: () => store.commit('increment'),
// 使用 action
asyncIncrement: () => store.dispatch('asyncIncrement')
}
}
}
#
看了官方文档,也查了一些资料,目前(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中可以用的方案,但是有两个缺点:
commit
和dispatch
都无法获得类型提示具体的看代码吧
仿照上面的文章,实现了一个简易的Store,好像也能凑合着用,感觉在Vuex5出来之前,也许在业务代码中再完善一下,采用这种方案可能更优雅一点?
两个Store,不存在嵌套关系了,root-store
中还是定义全局变量,types
定义类型:
// types.ts
export interface RootStates {
count: number;
}
export interface RootActions {
changeCountAct(payload: {newVal: number}): Promise;
}
在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({
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
字符串即可,全部代码在这里。