Vue3 TypeScript 配置 Vuex4
本文记录
Ts
版的Vue3
项目配置Vuex
。
目录 ./src/store 。
├─ store
│ ├─ index.ts
│ └─ interface.ts
首先看 ./src/store/index.ts ,这里是整个 store
的入口,里面定义并默认导出了 createStore
方法创建的 store
供整个项目使用。
import { InjectionKey } from 'vue';
import { createStore, Store } from 'vuex';
import RootStateTypes from '@/store/interface';
export default createStore<RootStateTypes>({
state: {
test:'test'
},
getters :{
},
mutations: {
CHANGE_TEST(state,val){
state.test = val;
}
},
actions: {
},
modules: {
testModule
}
});
export const key: InjectionKey<Store<RootStateTypes>> = Symbol('vue-store');
InjectionKey
方法为创建并使用定义state
时提供唯一的key
,用到了ES6
的Symbol
。
./src/store/interface.ts ,定义并导出了所用状态的接口。
export default interface RootStateTypes{
test: string;
}
./src/main.ts 中引入 store
import { createApp } from 'vue'
import store, { key } from './store'
...
createApp(App as any)
.use(store,key)
...
- 注意引入方式,这里引入了之前的唯一值
key
,并在createApp
的use
方法中和store
一起传入
测试
<template>
<div>
<p>{{moduleTest}}</p>
<button @click="handlerChnage">测试</button>
</div>
</template>
<script lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
import { key } from '@/store'
export default {
name: 'Test',
setup(){
const store = useStore(key);
let moduleTest = computed(()=>store.state.test);
const handlerChnage = () => {
store.commit('CHANGE_TEST','test2021');
}
return {
moduleTest,
handlerChnage
}
}
};
</script>
- 这里的
import { useStore } from 'vuex';
import { key } from '@/store';
两条语句分别引入useStore
和key
- 调用时
const store = useStore(key);
也要传入key
每次页面中使用时都要引入并传入 key
有些繁琐,我们可以在 ./src/store/index.ts 中统一导出。
import { InjectionKey } from 'vue';
import { createStore, Store, useStore as baseUseStore } from 'vuex';
import RootStateTypes from '@/store/interface';
export default createStore<RootStateTypes>({
state: {
test:'test'
},
getters :{
},
mutations: {
CHANGE_TEST(state,val){
state.test = val;
}
},
actions: {
},
modules: {
testModule
}
});
export const key: InjectionKey<Store<RootStateTypes>> = Symbol('vue-store');
export function useStore(){
return baseUseStore(key);
}
有两处改变:
useStore as baseUseStore
通过 TS 的 as 语法从vuex
中引入useStore
- 最后导出函数
useStore
,相当于包装一下vuex
中的useStore
方法,传入key
。
优化后再测试,代码会有所简化。
import { useStore } from '@/store';
export default {
...
setup(){
const store = useStore();
...
}
...
}
- 不需要引入
key
,也不需要把key
当作参数传入useStore
方法。
配置子模块
需要修改一下目录 ./src/store 。
├─ store
│ ├─ modules
│ │ ├─ test
│ │ │ ├─ index.ts
│ │ │ └─ interface.ts
│ ├─ index.ts
│ └─ interface.ts
-
创建 ./src/store/modules/ 文件夹。
-
为了测试现在此目录创建 test 文件夹。
-
test 相当于一个模块,在这个目录中再创建 index.ts
(state)
和 interface(接口)
。
./src/store/modules/test/index.ts
import { Module } from 'vuex';
import RootStateTypes from '@/store/interface';
import TestModuleTypes from '@/store/modules/test/interface';
const testModule: Module<TestModuleTypes,RootStateTypes> = {
namespaced: process.env.NODE_ENV !== 'production',
state: {
name: 'testmodule',
count: 0
},
mutations: {
ADD_COUNT(state){
state.count += 1;
}
},
actions: {
},
modules: {
}
}
export default testModule;
- 整体思路和 ./src/store/index.ts 差不多。只是从
vuex
中引入了Module
作为输出类型。 namespaced
命名空间的使用可提高模块的封装性和可复用性。
./src/store/modules/test/interface.ts
export default interface TestModuleTypes{
name: string;
count: number;
}
- 定义子模块的类型。
根模块两个文件的修改:
先看 ./src/store/interface.ts
import TestModuleTypes from '@/store/modules/test/interface'
export default interface RootStateTypes{
test: string;
}
export interface AllStateTypes extends RootStateTypes{
testModule: TestModuleTypes;
}
- 引入了刚定义的子模块类型
TestModuleTypes
- 通过接口继承的方式定义
AllStateTypes
接口,里面包含全部子模块接口。
再修改 ./src/store/index.ts
import { InjectionKey } from 'vue';
import { createStore, Store, useStore as baseUseStore } from 'vuex';
import RootStateTypes, { AllStateTypes } from '@/store/interface';
// 引入子模块
import testModule from '@/store/modules/test';
export default createStore<RootStateTypes>({
state: {
test:'test'
},
getters :{
},
mutations: {
CHANGE_TEST(state,val){
state.test = val;
}
},
actions: {
},
modules: {
testModule
}
});
export const key: InjectionKey<Store<RootStateTypes>> = Symbol('vue-store');
export function useStore<T=AllStateTypes>(){
return baseUseStore<T>(key);
}
- 引入刚定义的
AllStateTypes
子模块接口。 - 导入对应的子模块
testModule
,并把它加入到默认导出的createStore
的modules
中 - 最后导出的
useStore
方法添加默认是AllStateTypes
的泛型
测试子模块
<template>
<div>
<p>{{testModuleName}}</p>
<p>{{testModuleCount}}</p>
<button @click="handlerCount">添加</button>
</div>
</template>
<script lang="ts">
import { computed } from 'vue';
import { useStore } from '@/store';
export default {
name: 'Test',
setup(){
const store = useStore();
const testModuleName = computed(()=>store.state.testModule.name);
const testModuleCount = computed(()=>store.state.testModule.count);
const handlerCount = () => {
store.commit('testModule/ADD_COUNT');
}
return {
testModuleName,
testModuleCount,
handlerCount
}
}
};
</script>
- 通过
store.state.模块名
的方式引用到子模块。 - 注意
store.commit
传参的方式'testModule/ADD_COUNT'
,是'模块名/方法名'
转载自:https://juejin.cn/post/6992763925284519943