?- src
? ?- layout
? ? ? ?- index.ts ?# UI主框架(鉴权之后才能进的)
? ?- tools
? ? ? ?- auth.ts ? # 权限相关工具文件
? ?- router
? ? ? ?- router.tsx ?# 路由组件注册
? ? ? ?- routerMap.tsx ?# 路由表构建
? ? ? ?- privateRouter.ts ?# 权限路由组件
? ? ? ?- router.ts ?# 路由组件注册
? ?- pages #(下面都是随便弄的,要对自己的需求)
? ? ? ?- community.tsx ?# 社区压面
? ? ? ?- login.tsx ?# 登录界面
? ? ? ?- user.ts ?# 用户界面
? ? ? ?- book.ts ?# 书籍列表界面
??pnpm add antd --save # 因为是一个小案例,所以做了基础的UI开发
??pnpm add react-router-dom --save #(现在默认是V6版本的路由)
?/**
? * 设置token
? * @param token
? * @returns
? */
?export const setToken = (token: string) =>
? window.localStorage.setItem("auth_token", token);
?/**
? * 获取token
? * @returns
? */
?export const getToken = () => window.localStorage.getItem("auth_token");
?/**
? * 获取token
? * @returns
? */
?export const clearToken = () => window.localStorage.removeItem("auth_token");
?
仅仅以社区列表这个组件为例,其实就是每个具体页面准备好
?import React from "react";
?
?export default function Community() {
? return <div>社区列表界面</div>;
?}
?
?import React from "react";
?import ReactDOM from "react-dom/client";
?import App from "./App.tsx";
?import { BrowserRouter } from "react-router-dom";
?
?ReactDOM.createRoot(document.getElementById("root")!).render(
? <React.StrictMode>
? <BrowserRouter>
? <App />
? </BrowserRouter>
? </React.StrictMode>
? ? ?//这里配置的是BrowserRouter,根据需要,可选择这个或者HashRouter,两者差别这里就略过了,可以看看router v6基础篇或其他文章
?);
?
其实就是做了一个基本的
鉴权与过期
处理,自己项目如果有更多的需求,就在try里面加就可以了
?import { message } from "antd";
?import { ReactElement, useEffect } from "react";
?import { getToken } from "../tools/auth";
?import { useNavigate } from "react-router-dom";
?
?interface Props {
? children: ReactElement;
?}
?const PrivateRoute = ({ children }: Props) => {
? const navigator = useNavigate();
?
? // 对比时间戳是否超过48小时
? function isPast48Hours(timestamp: number): boolean {
? // 获取当前时间戳
? const currentTimestamp = Math.floor(Date.now() / 1000);
?
? // 计算时间差,单位为秒
? const timeDifference = currentTimestamp - timestamp;
?
? // 定义48小时的秒数
? const hours48InSeconds = 48 * 60 * 60;
?
? // 判断时间差是否超过48小时
? return timeDifference > hours48InSeconds;
? }
?
? useEffect(() => {
? try {
? const token: any = getToken();
? const tokenObj = JSON.parse(token);
? if (tokenObj === null || isPast48Hours(tokenObj.expired)) {
? message.warning("token过期,请重新登录");
? navigator(`/login`);
? }
? } catch (error) {
? message.warning("token过期,请重新登录");
? navigator(`/login`);
? }
? }, []);
? return <>{children}</>;
?};
?
?export default PrivateRoute;
?
这里没有直接用<Route/>组件爱你包裹,而是先用
js
对象形式维护了一套路由表数据,方便其他诸如:菜单/目录
等组件的复用
?import { Navigate } from "react-router-dom";
?import Login from "../pages/login";
?import User from "../pages/User";
?import Community from "../pages/Community";
?import Book from "../pages/Book";
?import Layout from "../layout";
?import PrivateRoute from "./privateRoute";
?export const routerMap = [
? {
? path: "/login",
? element: <Login />,
? },
? {
? path: "/",
? element: (
? <PrivateRoute>
? <Layout />
? </PrivateRoute>
? ),
? children: [
? {
? path: "/user",
? element: <User />,
? },
? {
? path: "/community",
? element: <Community />,
? },
? {
? path: "/book",
? element: <Book />,
? },
? ],
? },
? {
? path: "*",
? element: <Navigate to="/login" />,
? }, //其他没有被注册过的路径统一重定位到login
?];
?
其实就是将原先的路由表数据注册为路由组件
?
?import { useRoutes } from "react-router-dom";
?import { routerMap } from "./routerMap";
?
?function Router() {
? const routerTab = useRoutes(routerMap); //注册前端路由表
?
? return <div>{routerTab}</div>;
?}
?
?export default Router;
?
?import Router from "./router/router";
?
?function App() {
? return (
? <>
? <Router />
? </>
? );
?}
?
?export default App;
?
Layout布局组件,一个简单的小Demo来测试路由正确性,他会被权限组件
<PrivateRoute/>
包裹,受到保护
?import { Tabs, TabsProps } from "antd";
?import React from "react";
?import { Outlet, useNavigate } from "react-router-dom";
?import { clearToken } from "../tools/auth";
?export default function Layout() {
? const navigator = useNavigate();
? const items: TabsProps["items"] = [
? {
? key: "book",
? label: "书籍列表页面",
? },
? {
? key: "community",
? label: "社区列表页面",
? },
? {
? key: "user",
? label: "用户列表页面",
? },
? {
? key: "login",
? label: "退出登录",
? },
? ];
? const handleChangeRoute = (value: string) => {
? if (value === "login") {
? clearToken();
? }
? navigator(`/${value}`);
? };
? return (
? <>
? <div style={{ maxWidth: "500px", margin: "0 auto" }}>
? <div
? style={{
? display: "flex",
? alignItems: "center",
? justifyContent: "center",
? }}
? >
? <Tabs
? defaultActiveKey="community"
? size={"large"}
? items={items}
? onChange={(value) => {
? handleChangeRoute(value);
? }}
? />
? </div>
? <div
? style={{
? marginTop: "50px",
? display: "flex",
? alignItems: "center",
? justifyContent: "center",
? }}
? >
? <Outlet />
? </div>
? </div>
? </>
? );
?}
?
Login登录组件,一个简单的小Demo来测试路由正确性,他不会被权限组件
<PrivateRoute/>
包裹,可以随意进入
?import { Button } from "antd";
?import React from "react";
?import { setToken } from "../../tools/auth";
?import { useNavigate } from "react-router-dom";
?
?export default function Login() {
? const navigator = useNavigate();
? const handleLogin = () => {
? const preToken: object = {
? token: "hjsdbvfjhysebfjkd762354",
? expired: Date.now(),
? };
? console.log(JSON.stringify(preToken));
?
? setToken(JSON.stringify(preToken)); //模拟设置token
? navigator(`/`);
? };
?
? const handleRush = () => {
? navigator(`/`); //模拟强行进入主页
? };
? return (
? <div
? style={{
? marginTop: "30px",
? display: "flex",
? alignItems: "center",
? justifyContent: "center",
? }}
? >
? <Button
? type={"primary"}
? onClick={() => {
? handleLogin();
? }}
? style={{ marginRight: "15px" }}
? >
? 登录进入系统主页
? </Button>
? <Button
? type={"primary"}
? onClick={() => {
? handleRush();
? }}
? >
? 强行进入系统主页
? </Button>
? </div>
? );
?}
?
本实践没有过多的文本描述,多在代码中的注释。但通过此个实践了解学习之后,应该可以较好的掌握在的React Hooks项目中应用Router V6封装整个项目的路由系统,能够真正实现一次封装,多处收益
相关的配套实践Demo会上传Github开源
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。