Vue3.0 系列之 Vuex
通过本系列 可带你初步体验Vue3.0及其生态 🚀
系列文章:
前言
🤔 大致查了下网上的基本都是JS下使用Vuex,本文将完善Vue3.0的Ts下Vuex对应的State和Model的类型推断~😎
项目中引入Vuex
1. 通过脚手架安装
vue-cli 创建项目时通过勾选默认配置生成Vuex
- npm安装
npm install vuex --save
- 直接下载 / CDN引用
https://unpkg.com/vuex@4.0.0/dist/vuex.global.js 这样的方式指定特定的版本
以上废话是常规操作下面正式步入主题。
Vuex正常使用
在vue-cli 脚手架中生成的store中默认是这样的:
// store/index.ts
import { createStore } from "vuex";
export default createStore({
state: {},
mutations: {},
actions: {},
modules: {},
});
简单模拟项目中使用情况
// store/index.ts
import { createStore } from "vuex";
export default createStore({
state: {
name: "gby",
isVip: true,
hobby: ["足球", "看电影", "其他"],
},
mutations: {
// state不能直接更改, 在这里修改值
},
actions: {
// 业务操作...
},
modules: {
// user模块
// login模块
// ....
},
});
在Home.vue中实际使用:
发现vue文件调用下state没有name、isVip等属性的快捷提示更没有类型推断。
第一次封装
在官网中查看到 useStore 组合式函数类型声明,官网上是这么说的:
当使用组合式 API 编写 Vue 组件时,您可能希望
useStore返回类型化的 store。为了useStore能正确返回类型化的 store,必须执行以下步骤:
- 定义类型化的
InjectionKey。- 将 store 安装到 Vue 应用时提供类型化的
InjectionKey。- 将类型化的
InjectionKey传给useStore方法。
下面按照官网示例代码具体实现如下。
// store/index.ts
import { InjectionKey } from "vue"; // 定义类型化的 `InjectionKey`
import { createStore, Store } from "vuex";
// 为 store state 声明类型
export interface State {
name: string;
isVip: boolean;
hobby: string[];
}
// 1. 定义 injection key
export const key: InjectionKey<Store<State>> = Symbol();
export default createStore<State>({
state: {
name: "gby",
isVip: true,
hobby: ["足球", "看电影", "其他"],
},
...
});
// main.ts
...
import { createApp } from 'vue'
import { store, key } from "./store/index"
const app = createApp(App)
// 2. 将 store 安装到 Vue 应用时提供类型化的 `InjectionKey` 。
app.use(store, key)
...
app.mount("#app");
在Home.vue中使用需要将将类型化的 InjectionKey 传给 useStore 方法。:
// vue 组件
import { useStore } from "vuex";
import { key } from "@/store/index";
export default defineComponent({
...
setup () {
// 3. 将类型化的 `InjectionKey` 传给 `useStore` 方法。
const store = useStore(key)
retrun {}
}
})
实际使用效果如下:
从效果中可以看出来目前会对state有属性提示了并且在我給一个类型为String 的name赋值false会有错误提示啦。
第二次封装
以上虽然state中有类型推断了,但有有两个问题出现了:
- 每次在vue组件中使用的时候都需要引入store下定义的key(不方便)
- 一般都加在
modules里的state呢 也会有同样的提示么 ?
针对第一点:(每次在vue组件中使用不方便) 优化如下👇
// store/index.ts
import { createStore, Store, useStore as baseUseStore } from "vuex";
...
// 定义自己的 `useStore` 组合式函数
export function useStore(): Store<State> {
return baseUseStore(key);
}
这样每次在vue组件中使用就舒服了一点点
// import { useStore } from "vuex"; // 优化前
// import { key } from "@/store/index"; // 优化前
import { useStore } from "@/store/index"; // 优化后
export default defineComponent({
setup() {
// const store = useStore(key); // 优化前
const store = useStore(); // 优化后
}
})
现在我进一步添加一个模块,尝试一下在modules里的state也会有提示么。
// store/login/login.ts
import { State as RootSate } from "@/store/index";
import { Module } from "vuex";
export interface ILoginSate {
token: string; // token
lastLoginTime: string; // 上次登录时间
role: "VIP" | "SVIP" | "developer"; // 用户权限
}
// Module<S, R> => S 是当前模块state接口、R是全局定义的Store下的state接口
const loginModel: Module<ILoginSate, RootSate> = {
namespaced: true,
state: () => {
return {
token: "",
lastLoginTime: "",
role: "developer",
};
},
...
};
export default loginModel;
// store/index.ts
...
import loginModel from "./login/login";
...
export default createStore<State>({
...
modules: {
// login模块
login: loginModel,
},
});
在vue组件中调用发现是不会提示login及其模块下的state。(这个不是gif图)
这时感觉到应该是和key传入得约束有关,从次入口进一步封装如下:
// store/index.ts
...
import loginModel, { ILoginSate } from "./login/login"; // 将ILoginSate调用过来
// 新增
export interface State {
name: string;
isVip: boolean;
hobby: string[];
}
interface IModulesState {
login: ILoginSate;
// 其他模块
}
type IStoreType = State & IModulesState; // 合并类型
// 重新约束key
// export const key: InjectionKey<Store<State>> = Symbol();
export const key: InjectionKey<Store<IStoreType>> = Symbol();
// 重新约束useStore
// export function useStore(): Store<State> {
export function useStore(): Store<IStoreType> {
...
最终的运行效果
可看到有很好的提示state和modules和类型推断了😄,到这里就封装完成啦。
这上面的对于key的约束是可以单独提出来到一个type.ts文件中使我们的index.ts更加清晰、更加好维护。
按照这个模式在项目中实际使用起来吧。
【还有一种方法不采用 InjectionKey】
留坑(会新开一篇来写, 写好了会贴链接的)
结尾
- 体验Vue3及其生态 系列一 (搭建Vue3项目)
- 体验Vue3及其生态 系列二 (封装Vuex)
- 其他系列开发中...