React-Router 一站式攻略:从入门到精通,掌握路由搭建与权限管控

news/2025/1/8 13:32:14/

文章目录

    • 一、前言
    • 二、安装
      • 使用 npm 安装(推荐)
      • 使用 yarn 安装
    • 三、基础使用
      • 设置路由基础结构
      • 定义路由和组件关联
        • 直接在组件中定义路由
        • 定义单独一个路由表
      • 创建导航链接
    • 四、核心组件和功能
      • BrowserRouter 和 HashRouter
      • Route 组件
      • Link 组件
      • Switch 组件
    • 五、路由参数和嵌套路由
      • 路由参数
      • 嵌套路由
      • 嵌套路由层级加深及应用场景拓展
    • 六、编程式导航
    • 七、路由权限
      • 路由表
      • 权限组件
      • 404 页面

一、前言

react-router 库在 React 应用开发中扮演着至关重要的角色,它是实现页面路由管理的核心工具,能够让开发者根据不同的 URL 路径精准地渲染对应的组件,这对于构建流畅、交互性强的单页面应用(SPA)来说不可或缺。通过它,用户在浏览应用时无需频繁刷新整个页面,就能实现页面内容的动态切换,极大地提升了用户体验。
例如,许多知名的 React 应用,如一些大型的电商平台前端、在线办公软件等,都借助 react-router 来管理繁多的页面路由,实现复杂的功能模块切换和页面导航,使得用户可以方便快捷地在各个功能页面之间穿梭。

一般来说,React-Router v6 需要 React v16.8 或更高版本。因为 React-Router v6 利用了 React 的 Hooks 等特性,而 React v16.8 是第一个引入 Hooks 的版本。如果使用较低版本的 React,可能会导致 React-Router 无法正常工作或某些功能缺失。

二、安装

使用 npm 安装(推荐)

  1. 打开终端,进入 React 项目目录。
  2. 若没安装 React 项目,可用 Create React App 等创建新项目。
  3. 在项目目录下,运行 npm install react-router-dom 命令,安装成功后,可查看 node_modules 目录有无 react-router-dom 文件夹,或在代码文件导入相关模块(如 import { BrowserRouter } from'react-router-dom')验证,无报错即安装正确。

使用 yarn 安装

  1. 打开终端,进入 React 项目目录。
  2. 运行 yarn add react-router-dom 命令,完成后即可使用。

三、基础使用

项目 React 版本: 18.3.1;react-router-dom 版本:7.1.1。

设置路由基础结构

在 React 应用入口文件(通常是 index.jsmain.js),用 BrowserRouter(基于浏览器历史记录,URL 更自然)或 HashRouter(特殊部署需求或兼容旧浏览器)包裹整个应用。如在 main.js 中:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App.jsx';createRoot(document.getElementById('root')).render(<StrictMode><Router><App /></Router></StrictMode>
);

这里将 App 组件包裹在 RouterBrowserRouter 的别名)中,这样 App 组件及其子组件就可以访问到路由相关的功能。

定义路由和组件关联

App 组件或其他组件内,用 Route 组件定义路由规则。

直接在组件中定义路由

这种方式将路由定义直接放在组件内部,对于小型应用或者路由规则比较简单的情况,具有直观的优点。开发者可以一目了然地看到某个组件与具体路由路径的关联情况,并且路由规则与组件紧密结合,很适合组件自身内部的路由管理,尤其当组件是独立的功能模块时,能使模块功能更加内聚。

import React from 'react';
import { Route } from 'react-router-dom';
import Home from './Home';
import About from './About';
const App = () => {return (<div>{/* Route 组件定义路由,exact 精确匹配,确保路径完全是'/'才渲染 Home 组件,访问'/about'时不会渲染 Home 组件。访问'/'渲染 Home 组件,访问'/about'渲染 About 组件。*/}<Route exact path="/" component={Home} /><Route path="/about" component={About} /></div>);
}
export default App

然而,当应用规模逐渐变大,路由规则变得复杂时,这种写法会暴露出明显的缺点。比如在一个大型电商应用中,若有上百个路由都写在 App 组件内,代码会变得极为臃肿,查找特定路由关联的组件、修改路由参数等维护操作将变得异常繁琐,代码的可读性也会大打折扣,不利于后续的开发和维护。

定义单独一个路由表

单独创建一个路由表可以将所有的路由规则集中管理,这对于大型应用开发来说尤为重要。在开发过程中,开发者能够在一个文件中清晰地查看所有的路由路径、对应的组件以及可能的路由参数等关键信息。而且,路由表具备良好的复用性,比如在不同的布局组件(如具有不同侧边栏的布局)中,都可以引用这个统一的路由表来实现相同的路由功能,无需重复配置。同时,当需要对路由规则进行修改时,只需在路由表文件中操作即可,无需逐个在使用路由的组件中进行修改,极大地提高了开发效率和代码的可维护性。随着应用的不断发展,添加新路由也十分方便,并且对于路由的中间件(如权限验证,只有登录用户才能访问某些路由)等功能,在路由表中也能更便捷地进行配置。
创建 routes.js 文件定义路由表,集中管理路由规则。

import { lazy } from 'react';
// lazy 用于设置路由懒加载
const Home = lazy(() => import('@/pages/Home'));
const About = lazy(() => import('@/pages/About'));const Router = [{path: '/',element: <Home />},{path: '/about',element: <About />},// 设置 404 页面{path: '*',element: <NotFound />}
];export default Router

然后在 App 组件中使用这个路由表:

import router from './router';
import { Suspense } from 'react';
import { useRoutes } from 'react-router-dom';function App() {// useRoutes 依传入路由配置生成相应路由元素,代表应渲染组件树结构。const element = useRoutes(router);// Suspense 设页面跳转加载提示,组件加载时显示 fallback 指定内容。return <Suspense fallback={'loading...'}>{element}</Suspense>;
}export default App

此方式适用于大型应用,复用性好,修改路由便捷,还方便配置中间件(如权限验证)。

创建导航链接

使用 Link 组件来创建应用内部的导航链接,它与传统的 标签不同,当用户点击 Link 组件时,不会引起整个页面的刷新,而是通过 JavaScript 更新 URL 并触发相应的组件渲染,实现单页面应用内的无缝导航。

import React from 'react';
import { Link } from 'react-router-dom';const Navigation = () => {return (<nav>{/* Link 组件 to 属性指定导航目标路径,点击'Home'链接导航到根路径渲染 Home 组件,点击'About'链接导航到'/about'路径渲染 About 组件。*/}<Link to="/">Home</Link><Link to="/about">About</Link></nav>);
}export default Navigation

四、核心组件和功能

BrowserRouter 和 HashRouter

  • BrowserRouter:基于 HTML5 浏览器历史记录 API,URL 格式自然,无“#”符号,如电商产品详情页 URL 可为“/products/123”,利于 SEO。
  • HashRouter:用 URL 哈希部分管理路由,适用于旧浏览器或服务器不支持 HTML5 历史记录 API 的情况,部署在简单静态服务器上表现良好。

hash和history

Route 组件

Route 组件是核心,定义路由规则,关联 URL 路径与组件。

import React from 'react';
import { Route, BrowserRouter as Router } from 'react-router-dom';
import Home from './Home';
import About from './About';
const App = () => {return (<Router><Route exact path="/" component={Home} /><Route path="/about" component={About} /></Router>);
}
export default App

exact 属性精确匹配路径,避免误渲染。

Link 组件

与传统 <a> 标签不同,点击不刷新页面,更新 URL 触发组件渲染。

import React from 'react';
import { Link } from 'react-router-dom';
const Navigation = () => {return (<nav><Link to="/">Home</Link><Link to="/about">About</Link></nav>);
}
export default Navigation

Switch 组件

包裹一组 Route 组件,只渲染第一个匹配成功的 Route,防止多个组件同时渲染。

import React from 'react';
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom';
import Home from './Home';
import About from './About';
import NotFound from './NotFound';
const App = () => {return (<Router><Switch><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route component={NotFound} /></Switch></Router>);
}
export default App

在这个例子中,如果没有Switch组件,当用户访问一个不存在的路径时,NotFound组件和前面可能部分匹配的组件(比如Home组件)都可能会被渲染。有了Switch组件,只有NotFound组件会被渲染,因为前面的路由都没有匹配成功

五、路由参数和嵌套路由

路由参数

React-Router 允许在路由路径中定义参数。例如,在一个列表中,内容详情页的路由可以定义为 /articles/:id,其中 :id 是一个参数,表示详情的唯一标识符。在组件中可以通过 props.match.params 获取这个参数。

import React from 'react';
import { Route, BrowserRouter as Router } from 'react-router-dom';
const ArticleDetail = props => {const articleId = props.match.params.id;// 根据 articleId 获取文章详情并渲染return (<div><h1>Article Detail {articleId}</h1></div>);
}
const App = () => {return (<Router><Route path="/articles/:id" component={ArticleDetail} /></Router>);
}
export default App

用户访问 /articles/123 时,articleId 为“123”。

嵌套路由

复杂应用有嵌套路由情况,如电商产品详情页有评论区。

import React from 'react';
import { Route, BrowserRouter as Router, Switch } from 'react-router-dom';
import ProductDetail from './ProductDetail';
import ProductReviews from './ProductReviews';
const App = () => {return (<Router><Switch><Route path="/products/:id" component={ProductDetail}><Route path="/products/:id/reviews" component={ProductReviews} /></Route></Switch></Router>);
}
export default App

访问“/products/123/reviews”时,先渲染 ProductDetail 组件,再在其内部合适位置渲染 ProductReviews 组件。

嵌套路由层级加深及应用场景拓展

以企业级应用为例,展示部门详情页、员工列表页、员工个人详情页和员工绩效页等多层嵌套路由场景,通过合理配置实现页面有序切换。

import React from 'react';
import { Route, BrowserRouter as Router, Switch } from 'react-router-dom';const DepartmentDetail = props => {return (<div><h1>Department Detail</h1>{/* 展示部门相关信息 */}<Route path={`${props.match.path}/employees`} component={EmployeeList} /></div>);
}const EmployeeList = props => {return (<div><h2>Employee List</h </div>{/* 展示员工列表 */}<Route path={`${props.match.path}/:employeeId`} component={EmployeeDetail} /><Route path={`${props.match.path}/:employeeId/performance`} component={EmployeePerformance} /></div>);
}const EmployeeDetail = props => {const { employeeId } = props.match.params;return (<div><h3>Employee Detail - ID: {employeeId}</h3>{/* 展示员工个人详细信息 */}</div>);
}const EmployeePerformance = props => {const { employeeId } = props.match.params;return (<div><h3>Employee Performance - ID: {employeeId}</h3>{/* 展示员工绩效相关信息 */}</div>);
}const App = () => {return (<Router><Switch><Route path="/departments/:departmentId" component={DepartmentDetail} /></Switch></Router>);
}export default App

通过这样的复杂示例,可以更好理解嵌套路由在构建大型、功能丰富的应用中是如何发挥作用的,以及如何根据实际业务需求去设计和配置多层嵌套的路由结构,更好地应对复杂的页面关系和功能模块划分

六、编程式导航

Link 组件,React-Router 支持编程式导航,通过 history 对象实现,可在组件中用 props.history 获取(组件需通过 Route 组件渲染)。

import React from 'react';
import { Route, BrowserRouter as Router, useNavigate } from 'react-router-dom';
const MyComponent = props => {const Navigate = useNavigate();const handleClick = () => {Navigate('/about');}return (<div><button onClick={handleClick}>Go to About</button></div>);
}
const App = () => {return (<Router><Route path="/" component={MyComponent} /></Router>);
}
export default App

点击按钮,调用 handleClick 函数,导航到“/about”路径,适用于表单提交成功等内部逻辑导航。

七、路由权限

路由表

import { lazy } from 'react';
import Auth from './AuthRoute';
const Home = lazy(() => import('@/pages/Home'));
const About = lazy(() => import('@/pages/About'));
const List = lazy(() => import('@/pages/List'));
const User = lazy(() => import('@/pages/User'));
const NotFound = lazy(() => import('@/pages/NotFound'));const Router = [{path: '/',element: <Home />},{path: '/about',element: <About />},{path: '/app/',element: (// 自定义权限组件<Auth><BasicLayout /></Auth>),errorElement: <NotFound></NotFound>,children: [{path: 'list',element: <List />},{path: 'list/user',element: <User />}]},// 设置404页面{path: '*',element: <NotFound />}
];export default Router

权限组件

import { useEffect, useRef } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { message } from 'antd';
import useUpdateEffect from '@/components/useUpdateEffect';export default function Auth({ children }: any) {const location = useLocation().pathname;const didMountRef = useRef(false);const Navigate = useNavigate();const token = localStorage.getItem('token');useEffect(() => {if (didMountRef.current) {if (!token) {message.error('您未登录,将跳转');setTimeout(() => {Navigate('/login');}, 1000);}} else {didMountRef.current = true;}}, [token]);return children;
}

404 页面

import React from 'react';const CommonLine = props => (// 根据个人需求改动<div>未找到该页面</div>
);
export default CommonLine

http://www.ppmy.cn/news/1560625.html

相关文章

《大话设计模式》解读09-建造者模式

上篇文章,介绍了《大话设计模式》的第12章——外观模式。 本篇,来介绍《大话设计模式》的第13章——建造者模式。并通过python代码实现示例代码的功能。 1 建造者模式 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。…

Next.js 多语言 (1) | 中间件(Middleware)的设置与应用

当我们开发一个支持多语言的 Next.js 网站时&#xff0c;常常需要解决以下问题&#xff1a; 用户首次访问时&#xff0c;应该显示哪个语言版本&#xff1f; &#x1f914; 比如&#xff0c;用户访问 / 时&#xff0c;是展示 /en 还是 /de&#xff1f; SEO 是否能够抓取所有语言…

【JavaScript】变量-常量-数据类型-类型转换

目录 一、JavaScript 介绍 1. JavaScript &#xff08;是什么&#xff1f;&#xff09; 2. 作用&#xff08;做什么&#xff1f;&#xff09; 3. JavaScript的组成&#xff08;有什么&#xff1f;&#xff09; 3.1 ECMAScript: 3.2 Web APIs : 总结&#xff1a; 4. Jav…

算法复杂度O(1),O(n),O(logn),O(nlogn)意义|实现?

O(1) - 常数时间复杂度 在常数时间内完成操作的算法不会因为输入规模的变化而改变执行时间。 Java 例子&#xff1a; public class ConstantTimeExample {// 获取数组的第一个元素public static Integer getFirstElement(Integer[] array) {if (array.length 0) {return nu…

Maven项目集成SQL Server的完整教程:从驱动配置到封装优化

前言 在最近的系统对接过程中&#xff0c;由于对方团队不熟悉技术&#xff0c;最终选择直接提供 SQL Server 视图。本文详细记录了使用 Maven 集成 SQL Server 驱动的过程&#xff0c;以及从配置到查询的各个关键步骤&#xff0c;还包括注意事项与常见问题&#xff0c;希望对需…

Transformer算法实现IMDB文本分类任务和WMT14机器翻译任务

Transformer算法详解与PyTorch实现 目录 Transformer算法详解与PyTorch实现1. Transformer算法简介1.1 Transformer的优势1.2 Transformer的应用场景2. Transformer的核心组件2.1 自注意力机制(Self-Attention)2.2 多头注意力机制(Multi-Head Attention)2.3 位置编码(Posi…

LeetCode -Hot100 - 42. 接雨水

前言 本专栏主要通过“LeetCode 热题100”&#xff0c;来捡起自己本科阶段的算法知识与技巧。语言主要使用c/java。如果同样正在练习LeetCode 热题100的朋友欢迎关注或订阅本专栏。有疑问欢迎留言交流~ 题目描述 题目链接 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图…

mac无限刷新navicat试用时间

1.必看 原理就是删除一些文件&#xff0c;记录时间重置。建议买正版&#xff0c;禁止商用。 2.代码 #!/bin/bashset -efile$(defaults read /Applications/Navicat\ Premium.app/Contents/Info.plist)regex"CFBundleShortVersionString \"([^\.])" [[ $file…