0903Redux改造项目_用户信息_状态管理-react-仿低代码平台项目

文章目录

    • [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\].

相关推荐
果冻kk6 小时前
【实战教程】零基础搭建DeepSeek大模型聊天系统 - Spring Boot+React完整开发指南
spring boot·后端·react.js·deepseek
sunbyte16 小时前
Three.js + React 实战系列 - 项目展示区开发详解 Projects 组件(3D 模型 + 动效 + 状态切换)✨
javascript·react.js·3d
天天进步201521 小时前
React Hooks 深入浅出
javascript·react.js·ecmascript
哟哟耶耶21 小时前
react-13react中外部css引入以及style内联样式(动态className与动态style)
前端·css·react.js
qq_400552001 天前
【React Hooks原理 - useCallback、useMemo】
前端·react.js·前端框架
进取星辰2 天前
20、数据可视化:魔镜报表——React 19 图表集成
前端·react.js·信息可视化
寧笙(Lycode)2 天前
React实现B站评论Demo
前端·react.js·前端框架
莫问alicia2 天前
react + antd 实现后台管理系统
前端·react.js·前端框架·antd
小满zs3 天前
React-router v7 第七章(导航)
javascript·react.js·ecmascript