redux安装
yarn add react-redux @reduxjs/toolkit
yarn add @types/react-redux -D
redux基本使用
在src
目录下新建一个stroe
文件夹
store/index.tsx:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { configureStore } from "@reduxjs/toolkit"; import { projectListSlice } from "../screens/project-list/project-list.slice";
export const rootReducer = { projectList: projectListSlice.reducer, };
export const store = configureStore({ reducer: rootReducer, });
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
|
将这个提供状态的组件包裹其他app
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import React from "react"; import { ReactNode } from "react"; import { AuthProvider } from "./auth-context"; import { QueryClient, QueryClientProvider } from "react-query"; // 引入store, Provider import { Provider } from "react-redux"; import { store } from "../store/index";
export const AppProviders = ({ children }: { children: ReactNode }) => { return ( <Provider store={store}> // 包裹全局 <QueryClientProvider client={new QueryClient()}> <AuthProvider>{children}</AuthProvider> </QueryClientProvider> </Provider> ); };
|
创建切片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import { createSlice } from "@reduxjs/toolkit"; // 导入根store类型 import { RootState } from "../../store/index";
// 一个切片维护一个状态树 interface State { projectModalOpen: boolean; }
// 切片的state const initialState: State = { projectModalOpen: false, };
export const projectListSlice = createSlice({ name: "projectListSlice", // 表示slice本身 initialState, // slice切片状态的默认状态 // reducer依然是纯洁没有副作用 reducers: { openProjectModal(state) { // 为什么可以直接给state赋值,而不是返回一个新对象呢(usereducer)? // redux比较机制,a.name = 'dad' a === a true 这里reduxtoolkit借助了immer处理了, 它会创建一个新对象,将行为映射到新对象上,然后再返回 // 所以我们没有违反纯函数原则 // 其实这里相当于返回了一个新的state对象 state.projectModalOpen = true; }, closeProjectModal(state) { state.projectModalOpen = false; }, }, });
// 导出actions export const projectListActions = projectListSlice.actions;
// 导出切片状态,读取的是根状态里的,所以用一个函数 export const selectProjectModelOpen = (state: RootState) => state.projectList.projectModalOpen;
|
使用到组件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { Drawer } from "antd"; import React from "react"; import { useDispatch, useSelector } from "react-redux"; import { projectListActions } from "screens/project-list/project-list.slice"; import { selectProjectModelOpen } from "./project-list.slice";
export const ProjectModel = () => { const dispatch = useDispatch(); // useSelect是用来读总的状态树(store)里的状态的 const projectModalOpen = useSelector(selectProjectModelOpen); return ( <Drawer width={"100%"} visible={projectModalOpen} onClose={() => dispatch(projectListActions.closeProjectModal())} > <h1>projectModel</h1> </Drawer> ); };
|
redux和异步结合
利用redux来管理登录状态:
在store
下新建一个auth.slice.ts
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| import { UserLogin } from "utils/type"; import { createSlice } from "@reduxjs/toolkit"; import * as auth from "auth-provider"; import { AppDispatch, RootState } from "./index"; import { getMe } from "../api/project-list";
interface AuthForm { username: string; password: string; }
interface State { user: UserLogin | null; }
const boostrapUser = async () => { let user = null; const token = auth.getToken();
if (token) { await getMe(token).then((res) => { const data = res.data.user; user = data; }); } return user; };
// 初始状态 const initialState: State = { user: null, };
export const authSlice = createSlice({ name: "auth", initialState, reducers: { setUser(state, action) { // 更新状态 state.user = action.payload; }, }, });
// 方便使用 const { setUser } = authSlice.actions;
// 重点,在处理异步时的情况,返回一个函数(react-thunk) // 检测到返回函数的时候,react-thunk就会去执行那个函数 export const login = (form: AuthForm) => (dispatch: AppDispatch) => auth.login(form).then((user) => dispatch(setUser(user)));
export const register = (form: AuthForm) => (dispatch: AppDispatch) => auth.register(form).then((user) => dispatch(setUser(user)));
export const logout = () => (dispatch: AppDispatch) => auth.logout().then(() => dispatch(setUser(null)));
export const boostrap = () => (dispatch: AppDispatch) => boostrapUser().then((user) => dispatch(setUser(user)));
export const selectUser = (state: RootState) => state.auth.user;
|
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| export const useAuth = () => { // 规定dispatch的类型,这样用then不会报错 const dispatch: (...args: unknown[]) => Promise<UserLogin> = useDispatch(); // 取得state里的user const user = useSelector(selectUser); const login = useCallback( // d (form: AuthForm) => dispatch(authStore.login(form)), [dispatch] ); const register = useCallback( (form: AuthForm) => dispatch(authStore.register(form)), [dispatch] ); const logout = useCallback(() => dispatch(authStore.logout()), [dispatch]); return { user, login, register, logout, }; };
|
react-thunk
