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: {
increment(state) {
state.value++;
},
decrement(state) {
state.value--;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
使用 configureStore 定义状态机对象
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;
Provider 全局注入状态机对象
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";
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
异步操作
使用 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,
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;
const onFinish = async (accress: accressType) => {
console.log(accress);
await dispatch(getUserDataAction(accress));
navigate("/my");
};