文章目录
-
- [1 Redux管理用户信息](#1 Redux管理用户信息)
-
- [1.1 定义store和reducer](#1.1 定义store和reducer)
- [1.2 使用useSeletor](#1.2 使用useSeletor)
- [2 自定义Hook统一加载用户信息存储Redux](#2 自定义Hook统一加载用户信息存储Redux)
- [3 根据用户登录状态动态跳转页面](#3 根据用户登录状态动态跳转页面)
- 结语
1 Redux管理用户信息
1.1 定义store和reducer
src/store/userReducer.ts代码如下所示:
ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
export type UserStateType = {
username: string;
nickname: string;
};
const INIT_STATE = {
username: "",
nickname: "",
};
const userSlice = createSlice({
name: "user",
initialState: INIT_STATE,
reducers: {
loginReducer: (
state: UserStateType,
action: PayloadAction<UserStateType>
) => {
return action.payload;
},
logoutReducer: () => INIT_STATE,
},
});
export const { loginReducer, logoutReducer } = userSlice.actions;
export default userSlice.reducer;
src/store/index.ts代码如下所示:
ts
import { configureStore } from "@reduxjs/toolkit";
import userReducer, { UserStateType } from "./userReducer";
export type StateType = {
user: UserStateType
}
export default configureStore({
reducer: {
// 分模块
user: userReducer,
},
});
main.tsx代码如下所示:
tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
// import './index.css'
import App from "./App.tsx";
import store from "@/store";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
);
1.2 使用useSeletor
获取用户信息hook useGetUserInfo.ts代码如下所示:
ts
import { StateType } from "@/store";
import { UserStateType } from "@/store/userReducer";
import { useSelector } from "react-redux";
function useGetUserInfo() {
const { username, nickname } = useSelector<StateType>(
(state) => state.user
) as UserStateType;
return { username, nickname };
}
export default useGetUserInfo;
用户信息页UserInfo.tsx代码如下所示:
tsx
import { FC } from "react";
import { Link, useNavigate } from "react-router-dom";
// import { useRequest } from "ahooks";
import { Button } from "antd";
import { UserOutlined } from "@ant-design/icons";
import { LOGIN_PATHNAME } from "../router/index";
// import { getUserInfoApi } from "@/api/user";
import { removeToken } from "@/utils/userToken";
import useGetUserInfo from "@/hooks/useGetUserInfo";
import { useDispatch } from "react-redux";
import { logoutReducer } from "@/store/userReducer";
const UserInfo: FC = () => {
const nav = useNavigate();
// const { data } = useRequest(getUserInfoApi);
// const { username, nickname } = data || {};
const { username, nickname } = useGetUserInfo();
const dispatch = useDispatch();
function logout() {
// 清除用户信息和token信息
dispatch(logoutReducer());
removeToken();
// 跳转登录页
nav(LOGIN_PATHNAME);
}
const User = (
<>
<span style={{ color: "#e8e8e8" }}>
<UserOutlined />
{nickname}
</span>
<Button type="link" onClick={logout}>
退出
</Button>
</>
);
const Login = <Link to={LOGIN_PATHNAME}>登录</Link>;
return <>{username ? User : Login}</>;
};
export default UserInfo;
Logo.tsx页面在登录和不登录两种情况下,点击跳转不同页面,Logo.tsx代码如下所示:
tsx
import { FC, useEffect, useState } from "react";
import { Space, Typography } from "antd";
import { FormOutlined } from "@ant-design/icons";
import { Link } from "react-router-dom";
import styles from "./Logo.module.scss";
import useGetUserInfo from "@/hooks/useGetUserInfo";
import { LOGIN_PATHNAME } from "@/router";
const { Title } = Typography;
const Logo: FC = () => {
const { username } = useGetUserInfo();
const [pathname, setPathname] = useState("/");
useEffect(() => {
if (username) {
setPathname(LOGIN_PATHNAME);
}
}, [username]);
return (
<div className={styles.container}>
<Link to={pathname}>
<Space>
<Title>
<FormOutlined />
</Title>
<Title>调查问卷</Title>
</Space>
</Link>
</div>
);
};
export default Logo;
2 自定义Hook统一加载用户信息存储Redux
加载用户信息是从后端获取用户数据,useLoadUserData.ts代码如下图所示:
ts
import { useEffect, useState } from "react";
import { useRequest } from "ahooks";
import { useDispatch } from "react-redux";
import { loginReducer } from "@/store/userReducer";
import useGetUserInfo from "./useGetUserInfo";
import { getUserInfoApi } from "@/api/user";
function useLoadUserData() {
const [waitingUserData, setWaitingUserData] = useState(true);
const dispatch = useDispatch();
// ajax 加载用户信息
const { run } = useRequest(getUserInfoApi, {
manual: true,
onSuccess(res) {
const { username, nickname } = res;
dispatch(loginReducer({ username, nickname }));
},
onFinally() {
setWaitingUserData(false);
},
});
// 判断redux是否已经存在用户信息
const { username } = useGetUserInfo();
useEffect(() => {
if (username) {
setWaitingUserData(false);
return;
}
run();
}, [username]);
return { waitingUserData };
}
export default useLoadUserData;
加载用户信息后存储在Redux
3 根据用户登录状态动态跳转页面
页面调整判定:
- 用户已经登录,访问登录页或者注册页,需要跳转我的问卷页
- 用户未登录,访问首页,登录页和注册页放行
- 用户未登录,访问需要用户信息的页面,跳转登录页
自动以hook useNavPage.ts,代码如下所示:
ts
import { useEffect } from "react";
import useGetUserInfo from "./useGetUserInfo";
import { useLocation, useNavigate } from "react-router-dom";
import {
isLoginOrRegister,
isNotNeedUserInfo,
LOGIN_PATHNAME,
MANAGE_INDEX_PATHNAME,
} from "@/router";
function useNavPage(waitingUserData: boolean) {
const { username } = useGetUserInfo();
const { pathname } = useLocation();
const nav = useNavigate();
useEffect(() => {
if (waitingUserData) {
return;
}
// 已登录
if (username) {
if (isLoginOrRegister(pathname)) {
console.log("url", pathname);
// 不需要再登录或者注册
nav(MANAGE_INDEX_PATHNAME);
}
return;
}
// 未登录
if (isNotNeedUserInfo(pathname)) {
// 不需要用户信息
return;
} else {
nav(LOGIN_PATHNAME);
}
}, [waitingUserData, username, pathname]);
}
export default useNavPage;
在MainLayout.tsx和QuestionLayout.tsx如下位置调用:
tsx
// ...
import useNavPage from "@/hooks/useNavPage";
const { Header, Content, Footer } = Layout;
const MainLayout: FC = () => {
const { waitingUserData } = useLoadUserData();
useNavPage(waitingUserData)
// ....
};
export default MainLayout;
结语
❓QQ:806797785
⭐️仓库地址:https://gitee.com/gaogzhen
⭐️仓库地址:https://github.com/gaogzhen
1\][react官网](https://reactjs.org/)\[CP/OL\]. \[2\][Redux官网](https://redux.js.org/)\[CP/OL\]. \[3\][Redux Toolkit官网](https://redux-toolkit.js.org/)\[CP/OL\].