React学习笔记6:Redux介绍与使用

Redux介绍

Redux 是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行
作用:通过集中管理的方式管理应用的状态

Redux结构

为了职责清晰,Redux代码被分为三个核心的概念,我们学redux,其实就是学这三个核心概念之间的配合,三个概念分别是:

  1. state: 一个对象 存放着我们管理的数据
  2. action: 一个对象 用来描述你想怎么改数据
  3. 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 和 useSelector
hooks/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;

参考资料

  1. Redux 中文官网: https://cn.redux.js.org/tutorials/typescript-quick-start

Comments

No comments yet. Why don’t you start the discussion?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注