Mobx+Ts+持久化存储是一种强大的前端开发组合,它结合了 Mobx 状态管理、TypeScript 类型检查和持久化存储技术。Mobx 是一款功能丰富且易于使用的状态管理库,通过提供响应式的数据流和简洁的语法,有效解决了复杂应用中的数据管理问题。TypeScript 作为静态类型检查工具,可以帮助开发者在编码阶段捕获类型错误和提供智能提示,提高代码的可维护性和可读性。而持久化存储技术则可以将应用的数据长期保存,保证用户数据的可靠性和持续性。通过结合这三者,开发者可以构建出更健壮、可靠的前端应用。
封装 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();
akeAutoObservable
函数用于将类实例的属性和方法转换为可观察的,并自动追踪其变化。在这个例子中,makeAutoObservable
被调用时,第一个参数是当前类的实例this
,而第二个参数是一个对象,用于指定哪些属性或方法不应该被自动转换为可观察的。makePersistable
是 MobX Persist Store 库中提供的一个函数,用于将 MobX store 中的特定属性持久化到本地存储中,以便在应用程序重新加载时恢复它们的状态。它的主要作用是确保应用程序在重新加载后能够保持之前的状态,并且不会丢失任何重要的数据。name
:保存的 name,用于在 storage 中的名称标识,只要不和 storage 中其他名称重复就可以properties
:要保存的字段,这些字段会被保存在 name 对应的 storage 中,注意:不写在这里面的字段将不会被保存,刷新页面也将丢失:get 字段例外。get 数据会在数据返回后再自动计算storage
:保存的位置:看自己的业务情况选择,可以是 localStorage,sessionstorage
封装 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);
结语
以上就是关于 Mobx+Ts+持久化存储的全部内容,希望对大家有用,更多精彩内容请关注。