[🏆开箱即用🏆]的Mobx+Ts+持久化存储
封装Store
HomeStore示例
import { makeAutoObservable, runInAction } from "mobx";
import { setResult } from "@utils/util";
import { getTaskPendingApi } from "@/apis/modules/firstPage/firstPage.api";
import { toJS } from "mobx";
class HomeStore {
taskPendingList = {
count: 0,
list: [],
};
reminderCount: any = {
total: 0,
};
constructor() {
makeAutoObservable(this);
}
// 获取待办列表
async getTaskPending(data) {
const resultObj = {
api: getTaskPendingApi,
apiParams: data,
loading: "riskLoading",
result: "taskPendingList",
};
await setResult.call(this, resultObj);
}
// 清空消息数量
countEmpty() {
runInAction(() => {
this.reminderCount = {};
console.log("清空消息数量", toJS(this.reminderCount));
});
}
}
export default new HomeStore();
- 在构造函数中调用了
makeAutoObservable(this)
,这个函数来自MobX库,用于将类实例中的属性和方法转换为可观察的对象,使其能够被MobX追踪并自动更新相关组件。
setResult方法
/*
* 处理 store
* @param api 调用后端 api 接口
* @param apiParams 接口需要传递的参数
* @param loading 涉及到的 loading 状态属性名称
* @param result 需要修改的结果属性名称
* @param msg 调用接口成功提示信息
* @param ifConsole 是否打印调用接口信息到控制台
* @param callback 回调函数,用于处理接口返回结果
* @returns {Promise<any>}
*/
export async function setResult(this: any, {
api,
apiParams,
loading,
result,
msg,
ifConsole = false,
callback
}: any): Promise<any> {
if (typeof loading === "string" && loading.length > 0) {
this[loading] = true;
}
try {
const res = await api(apiParams);
runInAction(() => {
if (typeof loading === "string" && loading.length > 0) {
this[loading] = false;
}
if (typeof result === "string" && result.length > 0) {
this[result] = callback ? callback(res) : res;
}
});
if (ifConsole) {
console.log({ api, res });
}
if (msg) {
message.success(msg);
}
return await Promise.resolve(res)
} catch (e) {
runInAction(() => {
if (typeof loading === "string" && loading.length > 0) {
this[loading] = false;
}
});
if (ifConsole) {
console.log({ api, e });
}
await Promise.reject(e)
}
}
函数setResult
接收一个对象作为参数,包含了调用后端API所需的各种信息,如API函数、参数、loading状态属性名称、结果属性名称等。具体来说,它的参数如下:
api
:后端API接口函数。apiParams
:调用API时传递的参数。loading
:涉及到的loading状态属性的名称。result
:需要修改的结果属性的名称。msg
:调用接口成功时的提示信息。ifConsole
:一个布尔值,指示是否将调用接口信息打印到控制台。callback
:一个回调函数,用于处理接口返回结果。
函数首先根据传入的loading
参数设置相应的loading状态属性,然后调用后端API,并在获取到结果后使用runInAction
函数修改状态属性。如果设置了msg
,则会显示成功提示信息。最后,根据ifConsole
参数决定是否将调用接口信息打印到控制台。
如果调用过程中出现了错误,函数会在catch
块中处理,并同样根据需要修改loading状态属性和打印错误信息。
这个函数是一个通用的、用于调用后端API并处理结果的辅助函数。
持久化存储示例
import { makeAutoObservable, runInAction } from "mobx";
import { makePersistable } from "mobx-persist-store";
import { getEnumApi } from "@apis/common.api";
import { formatEnumList, setResult, handleLocalForage } from "@utils/util";
class CommonStore {
enumList: any = {};
appProvider: any = {};
constructor() {
makeAutoObservable(this, {
isModuleEnum: false,
});
//持久化存储
makePersistable(this, {
name: "enumList",
properties: ["enumList"],
storage: handleLocalForage,
});
}
get isModuleEnum() {
const list = window.location.pathname.split("/");
const pathname = `/${list[1]}`;
return formatEnumList(this.enumList.data[pathname]);
}
saveAppProvider(appProvider: any) {
runInAction(() => (this.appProvider = appProvider));
}
async getEnumList(data: any) {
const resultObj = {
api: getEnumApi,
results: "enumList",
apiParams: data,
};
await setResult.call(this, resultObj);
}
}
export default new CommonStore();
封装useStores
import React from "react";
import { MobXProviderContext } from "mobx-react";
interface ContextType {
stores: StoreType;
}
//函数声明,重载
function useStores(): StoreType;
function useStores<T extends keyof StoreType>(storeName: T): StoreType[T];
/*
*获取根 store或者指定store 名称数据
*@param storeName 指定了 store名称
*@returns typeof StoreType[storeName]
*/
function useStores<T extends keyof StoreType>(storeName?: T) {
const rootStore = React.useContext(MobXProviderContext);
const { stores } = rootStore as ContextType;
return storeName ? stores[storeName] : stores;
}
export { useStores };
/**
*获取所有模块store
*/
const files = Object.entries(
import.meta.glob("./modules/**/*.ts", { eager: true })
);
const _store: any = {};
files.forEach((item: any) => {
const key = `${item[0].split("/").at(-1).split(".")[0]}Store`;
_store[key] = item[1].default;
});
export type StoreType = typeof _store;
export default _store;
- Vite 支持使用特殊的
import.meta.glob
函数从文件系统导入多个模块,并且在构建时将它们分离为独立的 chunk。这种方式默认是异步加载模块的,通过动态导入实现。你可以遍历生成的modules
对象的键来访问相应的模块。
- 如果你希望直接引入所有的模块(同步加载使用),你可以传入
{ eager: true }
作为第二个参数。这样,模块会被转译为直接引入的形式。
🍋示例🍋:
好的,下面是你提供的示例代码以及它们在构建时被转译成的代码:
// 原始代码示例
const modules = import.meta.glob('./dir/*.js')
for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}
在构建时,上述代码会被转译成:
// 转译后的代码示例
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
'./dir/bar.js': () => import('./dir/bar.js')
}
for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}
另外,如果你希望以同步加载的形式引入所有的模块,你可以这样写:
javascriptCopy Code// 原始代码示例
const modules = import.meta.glob('./dir/*.js', { eager: true })
// 转译后的代码示例
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
'./dir/foo.js': __glob__0_0,
'./dir/bar.js': __glob__0_1
}
这样,所有模块会被转译成直接引入的形式,而不是通过动态导入异步加载。
导入使用
main.js全局导入
import { observer, Provider } from 'mobx-react'
import stores from '@/stores'
function Main() {
return <Provider stores={ stores }> {/* 应用的其余部分 */ } < /Provider>
}
export default observer(Main)
组件中使用
import { observer } from "mobx-react";
import { useEffect } from "react";
import { useStores } from "@/stores";
const FirstPage = () => {
const { homePageStore } = useStores();
useEffect(() => {
homePageStore.getEnumsList();
}, []);
return <></>;
};
export default observer(FirstPage);
转载自:https://juejin.cn/post/7365741765729484850