当前位置: 首页 > news >正文

第四章、路由配置

路由配置

一、安装依赖

npm install react-router-dom

二、推荐目录结构

src/
├── router/
│   └── index.tsx             # 路由配置文件
├── pages/
│   ├── Home.tsx
│   ├── About/
│   │   ├── index.tsx          
│   │   ├── LanguageI18n.tsx        
│   │   └── ThemeSwitcher.tsx           
│   ├── User/
│   │   ├── UserList.tsx
│   │   └── UserDetail.tsx
├── layout/
│   └── MainLayout.tsx        # 公共布局
├── App.tsx
└── index.tsx

三、基础路由配置(src/router/index.tsx

import React from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";import MainLayout from "@/layout/MainLayout";
import Home from "@/pages/Home";
import About from "@/pages/About/About";
import Company from "@/pages/About/LanguageI18n";
import Team from "@/pages/About/ThemeSwitcher";
import UserList from "@/pages/User/UserList";
import UserDetail from "@/pages/User/UserDetail";const router = createBrowserRouter([{path: "/",element: <MainLayout />,// 公共布局children: [{ index: true, element: <Home /> },// 默认路由{path: "about",element: <About />,children: [{ index: true, element: <Navigate to="languageI18n" replace /> },//设置默认子路由{ path: "languageI18n", element: <LanguageI18n /> },{ path: "themeSwitcher", element: <ThemeSwitcher /> },],},{ path: "users", element: <UserList /> },{ path: "users/:id", element: <UserDetail /> },// 动态参数],},
]);export default function AppRouter() {return <RouterProvider router={router} />;
}

四、在入口文件中加载路由

src/index.tsx

import React from "react";
import { createRoot } from "react-dom/client";
import "./styles/globals.css";
import "./index.css";
import { ThemeProvider } from "./context/ThemeContext";
import "./i18n";
import AppRouter from "./router";ReactDOM.createRoot(document.getElementById("root")!).render(<React.StrictMode><ThemeProvider><AppRouter /></ThemeProvider></React.StrictMode>
);

五、导航与跳转示例

src/pages/Home.tsx

import React from "react";
import { Link, useNavigate } from "react-router-dom";const Home: React.FC = () => {const navigate = useNavigate();const goToUser = () => {navigate("/users/42");};return (<div><h1>🏠 Home</h1><p>欢迎来到首页</p><Link to="/about">去关于页</Link><br /><button onClick={goToUser}>跳转到用户详情</button></div>);
};export default Home;

六、动态路由参数获取

src/pages/User/UserDetail.tsx

import React from "react";
import { useParams } from "react-router-dom";const UserDetail: React.FC = () => {const { id } = useParams<{ id: string }>();return (<div><h2>用户详情页</h2><p>当前用户ID: {id}</p></div>);
};export default UserDetail;

七、嵌套路由(src/pages/About/index.tsx

index.tsx 作为父级页面,需要提供导航入口,并包含一个 <Outlet /> 来渲染子页面内容。

import React from "react";
import { Link, Outlet } from "react-router-dom";const About: React.FC = () => {return (<div><h1>关于</h1><nav style={{ marginBottom: "1rem" }}><Link to="languageI18n">国际化切换</Link> | <Link to="themeSwitcher">主题切换</Link></nav>{/* 子路由出口 */}<Outlet /></div>);
};export default About;

九、子页面

src/pages/About/LanguageI18n.tsx

import LanguageSwitcher from "@/components/LanguageSwitcher";
import React from "react";
import { useTranslation } from "react-i18next";const LanguageI18n: React.FC = () => {const { t } = useTranslation();return (<div className="p-8"><h1>{t("welcome")}</h1><p>{t("language")}: {t("change_language")}</p><LanguageSwitcher /></div>);
};export default LanguageI18n;

src/pages/About/ThemeSwitcher.tsx

import { useTheme } from "@/context/ThemeContext";
import React from "react";const ThemeSwitcher: React.FC = () => {const { mode, theme, setMode, toggleTheme } = useTheme();return (<div style={{ padding: "2rem" }}><h1>🌗 React 三种主题模式</h1><p>当前模式:{mode}</p><p>当前实际主题:{theme}</p><div style={{ display: "flex", gap: "10px", marginBottom: "20px" }}><button onClick={() => setMode("light")}>亮色模式</button><button onClick={() => setMode("dark")}>暗色模式</button><button onClick={() => setMode("system")}>跟随系统</button><button onClick={toggleTheme}>手动切换主题</button></div><p>示例文字会根据主题自动变色。</p></div>);
};export default ThemeSwitcher;

十、路由懒加载(代码分割)

一、为什么要用懒加载?

推荐:React.lazy + Suspense
在开发中,React 项目文件越来越大,如果所有页面在首次加载时都被打包下载,会导致:

  • 首屏加载慢
  • 打包体积大
  • 用户等待时间长

解决方案: 按需加载(代码分割)
只有当用户访问某个路由页面时,才异步加载该页面代码。

这就是 React.lazy + Suspense 的核心功能。

二、改造后的 src/router/index.tsx

在(src/router/index.tsx)中

import React, { Suspense, lazy } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";// 使用 React.lazy 动态导入组件
const MainLayout = lazy(() => import("@/layout/MainLayout"));
const Home = lazy(() => import("@/pages/Home"));
const About = lazy(() => import("@/pages/About"));
const LanguageI18n = lazy(() => import("@/pages/About/languageI18n"));
const ThemeSwitcher = lazy(() => import("@/pages/About/ThemeSwitcher"));
const UserList = lazy(() => import("@/pages/User/UserList"));
const UserDetail = lazy(() => import("@/pages/User/UserDetail"));const router = createBrowserRouter([{path: "/",element: <MainLayout />,// 公共布局children: [{ index: true, element: <Home /> },// 默认路由{path: "about",element: <About />,children: [{ index: true, element: <Navigate to="languageI18n" replace /> },//设置默认子路由{ path: "languageI18n", element: <LanguageI18n /> },{ path: "themeSwitcher", element: <ThemeSwitcher /> },],},{ path: "users", element: <UserList /> },{ path: "users/:id", element: <UserDetail /> },// 动态参数],},
]);export default function AppRouter() {return <RouterProvider router={router} />;
}

三、全局 Suspense + Loading 动画

(1)Suspense的作用:

<Suspense fallback={<div>加载中...</div>}><About />
</Suspense>
  • Suspense 是一个占位组件
  • 当内部的 lazy 组件正在异步加载时,React 会渲染 fallback(占位内容);
  • 加载完成后,React 会自动替换为真实组件。
  • 这使得用户体验更加平滑(不会白屏)。

通俗理解:

“页面在加载时显示一段提示(比如‘加载中…’),加载完再显示真正的页面。”

(2) 全局 Suspense + 优雅 Loading 动画 的懒加载版本。

src/
├── router/
│   └── index.tsx             # 路由配置
├── components/
│   └── Loading.tsx           # 全局加载动画
├── layout/
│   └── MainLayout.tsx
└── index.tsx

全局加载动画组件src/components/Loading.tsx

import React from "react";const Loading: React.FC = () => {return (<divstyle={{height: "100vh",display: "flex",justifyContent: "center",alignItems: "center",flexDirection: "column",fontSize: "18px",color: "#555",}}><divstyle={{width: 40,height: 40,border: "4px solid #ccc",borderTopColor: "#4f46e5",borderRadius: "50%",animation: "spin 1s linear infinite",}}></div><p style={{ marginTop: 10 }}>页面加载中...</p><style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style></div>);
};export default Loading;

src/router/index.tsx

import Loading from "@/components/Loading";
//...// 用 Suspense 包裹整个路由系统
const AppRouter: React.FC = () => {return (<Suspense fallback={<Loading />}><RouterProvider router={router} /></Suspense>);
};export default AppRouter;

全局 Suspense 的优势

✅ 只写一次 fallback,所有懒加载页面共用
✅ 不需要在每个 <Route><Suspense>
✅ 结构更清晰,可直接替换为统一的动画或骨架屏

十一、其他问题

1.别名使用

import MainLayout from "@/layout/MainLayout"; 时却报错。
这个问题通常是因为 TypeScript 编译器无法识别 Webpack 的别名设置。Webpack 在打包时会处理这些别名,但 TypeScript 在编译时也需要知道这些别名。需要同时在 Webpack 和 TypeScript 中配置别名。

修改 tsconfig.json

{"compilerOptions": {..."baseUrl": ".","paths": {"@/*": ["src/*"]}},"include": ["src/**/*"],"exclude": ["node_modules"]
}

完善 Webpack 配置webpack.common.js

  resolve: {extensions: ['.ts', '.tsx', '.js', '.jsx'],alias: {'@': path.resolve(__dirname, '../src'),},},

注意补充完后,重启一下

2.React Router DOM 最常用方法和组件表格

核心组件
组件用途示例使用频率
BrowserRouter应用根路由容器<BrowserRouter><App /></BrowserRouter>⭐⭐⭐⭐⭐
Routes路由配置容器<Routes><Route ... /></Routes>⭐⭐⭐⭐⭐
Route定义单个路由<Route path="/" element={<Home />} />⭐⭐⭐⭐⭐
Link声明式导航链接<Link to="/about">关于</Link>⭐⭐⭐⭐⭐
Outlet嵌套路由渲染位置<Outlet />⭐⭐⭐⭐
NavLink带激活状态的链接<NavLink to="/" className={({isActive}) => ...}>⭐⭐⭐
常用 Hooks
Hook用途示例使用频率
useNavigate编程式导航const navigate = useNavigate(); navigate('/path')⭐⭐⭐⭐⭐
useParams获取路由参数const { id } = useParams();⭐⭐⭐⭐⭐
useLocation获取当前位置信息const location = useLocation();⭐⭐⭐⭐
useSearchParams处理URL查询参数const [params, setParams] = useSearchParams();⭐⭐⭐⭐
useRoutes对象形式定义路由const routes = useRoutes([...]);⭐⭐⭐
导航组件对比
特性LinkNavLinkuseNavigate
类型声明式声明式编程式
激活状态
使用场景普通链接导航菜单事件处理、表单提交
参数获取对比
场景使用 Hook示例
路径参数useParams/user/:idconst {id} = useParams()
查询参数useSearchParams?page=1const [params] = useSearchParams()
状态传递useLocationnavigate('/path', {state: {data}})
路由配置及菜单数据

(1)分清楚路由配置的数据和菜单导航的渲染数据
在这里插入图片描述

在菜单渲染数据里子菜单漏写父路径会导致404

在这里插入图片描述

(2)<Outlet />子路由出口

src/pages/About/index.tsx
在这里插入图片描述

在这里插入图片描述

MainLayout.tsx

首页、关于、用户等都是子路由
在这里插入图片描述

在这里插入图片描述

所以MainLayout.tsx是公共布局,主布局页面

http://www.dtcms.com/a/525038.html

相关文章:

  • Node.js:JavaScript的服务器端革命
  • C++动态内存管理详解:new/delete与malloc/free深度对比
  • 危险网站提示门户网站是如何做引流的
  • 网站代码怎么打开清风网站建设
  • Spring Boot 1.x、2.x 3.x区别汇总
  • 房产网站建设接单公关策划书模板范文
  • three.js加载三维GLB文件,查看三维模型
  • 在Linux中以root的身份进入GNOME桌面
  • 国内wordpress主题网站广元建设网站
  • 做网站哪家便宜搭建网站需要什么技能
  • 网站打不开第二天不收录啦好用的建站系统
  • 前端实现大文件上传全流程详解
  • pom.xml文件中io.swagger的swagger-bootstrap-ui和springfox-bean-validators未找到
  • ClickHouse 数据库应用场景与示例
  • 海口网红图书馆在哪里灰色行业关键词优化
  • 网站建设免费的蔬莱网站建设
  • MATLAB 实现图像边缘检测与轮廓提取(Canny、Sobel、Prewitt 算子对比)
  • 个人网站建站的流程合肥网站建合肥网站建设找蓝领商务
  • 从golang从GMP模型到分布式架构:无锁化思想的高并发实践
  • 前端开发【工具函数】基于dayjs 封装的DateUtils工具函数,可以直接拿着使用
  • 【开源项目分享】JNSM1.2.0,支持批量管理的jar包安装成Windows服务可视化工具,基于Java实现的支持批量管理已经安装服务的可视化工具
  • 【Diffusion Model】IDDPM代码详解
  • 匿名网站建设系统重装后 怎么装wordpress
  • 建筑网站知名度字形分析网站
  • C++中的Aggregate initialization
  • 鸿蒙Harmony实战开发教学(No.8)-Hyperlink超链接组件基础到进阶篇
  • Ubuntu开启SSH
  • 郑州营销网站托管和淘宝同时做电商的网站
  • 删除网站备案百度搜索风云榜手机版
  • 枣庄市网站建设跨境电商亚马逊开店流程