前言
上一篇我们介绍了脚手架搭建的接口篇,如不清楚的话,可以移步:React+ts+vite脚手架搭建(二)【接口篇】

状态管理也是每个脚手架都必备的,用于统一管理应用数据,解决状态共享等难题。
这里我用的是rematch,也可以替换成别的状态管理库,比如zustand
具体步骤
下载依赖
js
yarn add react-redux @rematch/core redux-logger @types/redux-logger
react-redux
:提供<Provider>
组件,让Redux
的store
能被整个React
组件树访问@rematch/core
:基于Redux
的轻量级封装,简化了Redux
的使用逻辑redux-logger
:是Redux
的中间件,用于在控制台打印状态变化的日志,方便调试@types/redux-logger
:redux-logger
的TypeScript
类型定义文件
新建文件
在之前创建的项目目录结构中的状态区新建store.ts
和models.ts
文件:

初始化store
这里我们将初始化store
并导出,最后将store
实例放在最顶层组件,用于存储全局的状态和数据:
init
初始化store
函数- 添加配置
models
- 传入从
models
引入的models
,这个模型定义了应用的所有状态和修改逻辑
- 传入从
- 配置
Redux
中间件- 添加
createLogger
,用于在控制台输出状态变化信息便于调试
- 添加
- 定义
Store
类型,并导出- 用于在需要传入
store
实例的地方提供类型约束
- 用于在需要传入
- 定义
Dispatch
类型,并导出- 可以在组件中使用
dispatch
时,获得类型提示和校验
- 可以在组件中使用
- 定义RootState类型,并导出
- 用于在组件中获取状态时提供类型提示(如
useSelector
)
- 用于在组件中获取状态时提供类型提示(如
js
// init: 用于初始化 Rematch store 的函数
// RematchDispatch: 类型,用于定义符合 Rematch 规范的 dispatch 类型
// RematchRootState: 类型,用于生成根状态的类型
import { init, RematchDispatch, RematchRootState } from "@rematch/core";
// 从 redux-logger 导入日志工具,用于在控制台打印 Redux 状态变化日志
import { createLogger } from "redux-logger";
// 导入应用的模型定义:
// models: 实际的状态模型集合(包含各个模块的 state、reducers、effects 等)
// RootModel: 根模型的类型定义,用于类型推导
import { models, RootModel } from "./models";
// 初始化 Rematch store
export const store = init({
// 传入应用的状态模型,这些模型定义了应用的所有状态和修改逻辑
models,
// Redux 相关配置
redux: {
// 配置 Redux 中间件,这里添加了日志中间件
// createLogger() 会生成一个日志中间件,用于在控制台输出状态变化信息(便于调试)
middlewares: [createLogger()],
},
});
// 定义 Store 类型,其类型与初始化后的 store 保持一致
// 用于在需要传入 store 实例的地方提供类型约束
export type Store = typeof store;
// 定义 Dispatch 类型,基于 RootModel 生成符合 Rematch 规范的 dispatch 类型
// 在组件中使用 dispatch 时会获得类型提示和校验
export type Dispatch = RematchDispatch<RootModel>;
// 定义 RootState 类型,基于 RootModel 生成根状态的类型
// 用于在组件中获取状态时提供类型提示(如使用 useSelector 时)
export type RootState = RematchRootState<RootModel>;
初始化models
我们在上面初始化store.ts
文件时,引用了models.ts
文件里的两个变量:models
和RootModel
,我们现在在models.ts
文件中定义这两个变量:
js
import { Models } from '@rematch/core';
export interface RootModel extends Models<RootModel> {
}
export const models: RootModel = {
}
RootModel接口定义了整个应用的状态模型类型规范;
models对象是实际存放各个业务模块状态类型的容器;
我们先将这两个地方的内容空出来,后面再进行补充。
将Provider作为应用的顶层组件
使用状态管理的最后一步,就是将状态实例给放到全局,我们在main.tsx
文件中修改:
- 引入
Provider
组件 - 引入
store
实例 Provider
组件包裹根组件并传入store
实例
js
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { HashRouter } from "react-router-dom";
import './style/index.css'
import App from './App'
import { Provider } from "react-redux";
import { store } from "./model/store";
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Provider store={store}>
<HashRouter>
<App />
</HashRouter>
</Provider>
</StrictMode>,
)
好了以上的rematch
的前期使用必备的逻辑都已搭建完毕,后续我们可以正式在业务模块中使用了。
使用
现在我们实际使用一下,我们这里以用户信息为例子,假设我们从一个接口中获取用户信息,并且存储在全局,且展示出来:
mock用户信息接口
- 我这里用
Promise
来模拟请求 - 这里的类型我用了
any
,大家可以根据自己项目的实际情况来声明类型

js
export function getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
resolve({
name: "张三",
age: 18,
})
})
}
新建homeModel.ts
- 添加状态类型------
IhomeModelState
- 给状态赋予初始值------
useInfo: {}
- 在
reducers
中定义更新状态的函数 - 在
effects
中定义需要异步更改状态的逻辑

js
import { createModel } from '@rematch/core';
import { RootModel } from '../../../model/models';
interface IhomeModelState {
}
export const home = createModel<RootModel>()({
state: {
useInfo: {}
} as IhomeModelState, // initial state
reducers: {
setUseInfo(state, payload: any = {}) {
return {
...state,
useInfo: payload
};
},
},
effects: (dispatch) => ({
}),
});
填充业务模块model

js
import { Models } from "@rematch/core";
import { home } from "../page/home/model/homeModel";
export interface RootModel extends Models<RootModel> {
home: typeof home;
}
export const models: RootModel = {
home,
};
home页调用接口更新状态
这样我们就能在页面中看到最新的状态


js
import { useDispatch, useSelector } from 'react-redux';
import { Dispatch } from "../../model/store";
import { RootModel } from '../../model/models';
import { useEffect } from 'react';
import { getUserInfo } from '../../service';
const Home = () => {
const dispatch = useDispatch<Dispatch>();
const useInfo = useSelector((state: RootModel) => state.home.useInfo);
useEffect(() => {
getUserInfo().then((res) => {
dispatch.home.setUseInfo(res);
});
}, []);
return (
<div>
<h1>Home</h1>
<p>useInfo: {JSON.stringify(useInfo?.name)}</p>
<p>useInfo: {JSON.stringify(useInfo?.age)}</p>
</div>
);
};
export default Home;
补充
之前我们在初始化homeModel.ts文件的时候,有个effects的模块待补充,这里之前的解释是说要需要补充异步更改状态的逻辑 接口请求就是异步的,所以我们上述请求用户信息的接口我们也可以写在这里面:

js
import { createModel } from '@rematch/core';
import { RootModel } from '../../../model/models';
import { getUserInfo } from '../../../service';
interface IhomeModelState {
}
export const home = createModel<RootModel>()({
state: {
useInfo: {}
} as IhomeModelState, // initial state
reducers: {
setUseInfo(state, payload: any = {}) {
return {
...state,
useInfo: payload
};
},
},
effects: (dispatch) => ({
async getUserInfo2() {
const res = await getUserInfo();
dispatch.home.setUseInfo(res);
},
}),
});
然后再useEffect中使用

js
import { useDispatch, useSelector } from 'react-redux';
import { Dispatch } from "../../model/store";
import { RootModel } from '../../model/models';
import { useEffect } from 'react';
import { getUserInfo } from '../../service';
const Home = () => {
const dispatch = useDispatch<Dispatch>();
const useInfo = useSelector((state: RootModel) => state.home.useInfo);
useEffect(() => {
// getUserInfo().then((res) => {
// dispatch.home.setUseInfo(res);
// });
dispatch.home.getUserInfo2();
}, []);
return (
<div>
<h1>Home</h1>
<p>useInfo: {JSON.stringify(useInfo?.name)}</p>
<p>useInfo: {JSON.stringify(useInfo?.age)}</p>
</div>
);
};
export default Home;
当前聪明的你可能会想到将页面中的所有接口都写在effects
里面,然后在homeModel
文件中统一管理所有接口的数据状态,你也许可以尝试尝试
踩踩坑
本期暂无小坑~
总结
好了,以上就是我们状态管理相关的内容,希望对你有所帮助~