RTK(简化 Redux)

202 阅读2分钟

RTK(简化 Redux)

  • RTK 内部默认集成了异步模块、默认集成了 immer

安装

yarn add @reduxjs/toolkit react-redux
或
npm i @reduxjs/toolkit react-redux

使用

使用 createSlice 定义状态机子模块

import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
  name: "counter",
  initialState: {
    //初始化数据
    value: 100,
  },
  reducers: {
    //此处的reducers,对action跟reducer做了默认的映射
    increment(state) {
      state.value++;
    },
    decrement(state) {
      state.value--;
    },
  },
});
export const { increment, decrement } = counterSlice.actions; // 单独抛出action,方便组件触发
export default counterSlice.reducer; //抛出reducer,供状态机初始化使用

使用 configureStore 定义状态机对象

// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import count from "./features/count";
const store = configureStore({
  reducer: {
    count,
  },
});
export default store;

export type RootState = ReturnType<typeof store.getState>; //获取状态机数据类型
export type AppDispatch = typeof store.dispatch; //获取dispatch方法的类型

Provider 全局注入状态机对象

// main.jsx
import { Provider } from "react-redux";
import store from "./store";

ReactDOM.createRoot(document.getElementById("root")).render(
  <Provider store={store}>
    <App />
  </Provider>
);

在组件中操作状态机

  • useSelector 提取数据
  • useDispatch 触发状态机方法
  • 可以用下面封装的useAppSelector 以及useAppDispatch 代替useSelector、useDispatch
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "../../store";
import { Button } from "antd-mobile";
import { increment } from "../../store/features/count";
export interface ICompAProps {}

export default function CompA(props: ICompAProps) {
  const { count } = useSelector((state: RootState) => state);
  const dispatch = useDispatch();
  console.log("状态机数据", count);

  return (
    <div>
      <h1>A组件,{count.num}</h1>
      <Button
        color="primary"
        onClick={() => {
          dispatch(increment());
        }}
      >
        +
      </Button>
    </div>
  );
}

useSelector 封装

  • 避免后续组件使用时需要单独引入每一次
import { useSelector, useDispatch, TypedUseSelectorHook } from "react-redux";
import { AppDispatch, RootState } from "./index";

// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch; // () => AppDispatch 代表返回的是一个函数
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector; // TypedUseSelectorHook<RootState> 类型注解
// 以后组件中不要再单独使用 useSelector, useDispatch,使用useAppSelector 以及useAppDispatch 代替

异步操作

使用 createAsyncThunk 请求数据

//登录饲用异步的例子
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { userLogin } from "../../api/user";
import { accressType, userInfoType } from "../../types/user";
import store2 from "store2";

interface initStateType {
  isLoading: boolean;
  isLogin: boolean;
  userInfo: userInfoType | null;
}

let initState: initStateType = {
  isLoading: false, //控制登录的loading状态
  isLogin: false, //判断登录状态
  userInfo: null, //存放用户信息
};

const userInfo = store2.get("move-userInfo");
if (userInfo) {
  initState.userInfo = userInfo;
}
const userSlice = createSlice({
  name: "user",
  initialState: {
    initState,
  },
  reducers: {
    exitLogin(state) {
      state.initState.userInfo = null;
      store2.remove("move-userInfo");
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(getUserDataAction.pending, (state) => {
        state.initState.isLoading = true;
      })
      .addCase(getUserDataAction.fulfilled, (state, action) => {
        state.initState.isLoading = false;
        state.initState.isLogin = true;
        state.initState.userInfo = action.payload;
        console.log("登录成功", action.payload);
        store2.set("move-userInfo", action.payload);
      })
      .addCase(getUserDataAction.rejected, (state) => {
        state.initState.isLoading = false;
        state.initState.isLogin = false;
        state.initState.userInfo = null;
        console.log("登录失败");
      });
  },
});

export const getUserDataAction = createAsyncThunk(
  "userInfo",
  async (accress: accressType) => {
    const res = await userLogin(accress);
    return res.data;
  }
);

export const { exitLogin } = userSlice.actions;
export default userSlice.reducer;


//在.tsx中使用
 const onFinish = async (accress: accressType) => {
    console.log(accress);
    await dispatch(getUserDataAction(accress));
    navigate("/my");
  };