Redux介绍
Redux 是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行
作用:通过集中管理的方式管理应用的状态
Redux结构
为了职责清晰,Redux代码被分为三个核心的概念,我们学redux,其实就是学这三个核心概念之间的配合,三个概念分别是:
- state: 一个对象 存放着我们管理的数据
- action: 一个对象 用来描述你想怎么改数据
- reducer: 一个函数 根据action的描述更新state
Redux使用步骤
- 定义一个 reducer 函数 (根据当前想要做的修改返回一个新的状态)
- 使用createStore方法传入 reducer函数 生成一个store实例对象
- 使用store实例的 subscribe方法 订阅数据的变化(数据一旦变化,可以得到通知)
- 使用store实例的 dispatch方法提交action对象 触发数据变化(告诉reducer你想怎么改数据)
- 使用store实例的 getState方法 获取最新的状态数据更新到视图中
安装依赖
npm i @reduxjs/toolkit react-redux
项目目录结构
定义根 State 和 Dispatch 类型
在 Redux store 文件(通常是 store.ts)中定义 RootState 类型和 AppDispatch 类型。这些类型将从store本身中推断出来,以便在其他文件中引用。
store/index.tsx
关键代码:
// 从 store 本身推断出 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>;
// 推断出类型: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
完整代码
import { configureStore } from "@reduxjs/toolkit";
import billReducer from "@/store/modules/billStore";
const store = configureStore({
reducer: {
bill: billReducer,
},
});
// 从 store 本身推断出 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>;
// 推断出类型: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
export default store;
定义 Hooks 类型
创建一个名为hooks.ts的文件,定义预先类型化的useDispatch和useSelector钩子,以便在应用程序中使用。store/hooks.tsx
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './index'
// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
定义 slice state 和 action 类型
这部分和 js + Redux 区别不大,唯一的区别就是要用 as
语句类转换初始 state。store/modules/billStore.tsx
关键代码:
initialState: {
billList: [] as Bill[],
},
完整代码:
import { Dispatch, PayloadAction, createSlice } from "@reduxjs/toolkit";
import { fetchBill } from "@/apis/bill";
import { Bill } from "@/model";
const billStore = createSlice({
name: "billList",
initialState: {
billList: [] as Bill[],
},
reducers: {
setBillList: (state, action: PayloadAction<Bill[]>) => {
state.billList = action.payload;
},
},
});
const { setBillList } = billStore.actions;
async function getBillList(dispatch: Dispatch): Promise<void> {
const billList = await fetchBill();
dispatch(setBillList(billList));
}
export { setBillList, getBillList };
const billReducer = billStore.reducer;
export default billReducer;
在组件中使用标注过类型的钩子
在组建或 hook 代码中使用 useDispatch 和 useSelectorhooks/useBillList.ts
关键代码:
const dispatch = useAppDispatch();
const { billList } = useAppSelector((state) => state.bill);
完整代码:
import { useAppDispatch, useAppSelector } from "@/store/hooks";
import { useEffect } from "react";
import { getBillList } from "@/store/modules/billStore";
import { Bill } from "@/model";
function useBillList(): { billList: Bill[] } {
const dispatch = useAppDispatch();
const { billList } = useAppSelector((state) => state.bill);
useEffect(() => {
getBillList(dispatch);
}, [dispatch]);
return { billList };
}
export { useBillList };
在组件中使用
与ts区别不大pages/Layout/index.tsx
import { useBillList } from "@/hooks/useBillList";
function Layout() {
const { billList } = useBillList();
return (
<div>
这里是 Layout
<div>{billList.map((bill) => bill.money)}</div>
</div>
);
}
export default Layout;