别再踩坑!React Router 路由匹配、嵌套导航全解析(附避坑指南)

一、React Router 的基本概念

1. 什么是 React Router?

React Router 就是SPA(单页应用)的导航控制器。想象你有一个乐高城堡,每个房间(页面)都通过走廊(路由)连接。当你点击导航按钮时,城堡会"魔术般"地切换房间,而URL会自动更新。

2. 主要特性

  • 🧩 声明式路由:用组件方式配置路由规则
  • 🌳 嵌套路由:支持多层页面结构
  • 🔄 动态路由:URL中可以包含变量参数
  • 🛠️ 程序化导航:像操作数组一样控制跳转
  • 📁 浏览器历史记录:支持前进/后退按钮

二、核心组件实战解析

1. BrowserRouter - 路由系统的基石

jsx 复制代码
import { BrowserRouter } from 'react-router-dom';

function Root() {
  return (
    <BrowserRouter>
      <App />
    </BrowserRouter>
  );
}

效果演示:包裹整个应用后,所有路由功能将被激活

2. Route - 路由规则定义器

jsx 复制代码
<Switch>
  <Route exact path="/home" component={Home} />  //exact  严格匹配
  <Route path="/about" component={About} />
</Switch>

关键点:path指定路径,component指定对应组件

jsx 复制代码
<Link to="/">首页</Link>
<Link to="/about">关于</Link>

对比传统a标签:点击不会刷新页面,实现SPA体验

4. Switch - 路由匹配开关

jsx 复制代码
//可提高路由匹配效率
<Switch>
  <Route path="/home" component={Home} />
  <Route path="/about" component={About} />
</Switch>

作用:只渲染第一个匹配的路由,避免多组件同时显示

三、从0到1搭建路由系统

1. 安装React Router

可以使用npm或yarn安装React Router DOM

npm install react-router-dom

2.创建路由组件

pages/Home/index.jsx

jsx 复制代码
import React, { Component } from 'react'

export default class About extends Component {
	render() {
		// console.log('About组件收到的props是',this.props);
		return (
			<h3>我是About的内容</h3>
		)
	}
}

pages/About/index.jsx

jsx 复制代码
import React, { Component } from 'react'

export default class Home extends Component {
	render() {
		return (
			<h3>我是Home的内容</h3>
		)
	}
}

3.创建一般组件

components/Header

jsx 复制代码
import React, { Component } from 'react'

export default class Header extends Component {
	render() {
		// console.log('Header组件收到的props是',this.props);
		return (
			<div className="page-header"><h2>React Router Demo</h2></div>
		)
	}
}

4.封装NavLink(实现高亮效果)

components/MyNavLink

jsx 复制代码
import React, { Component } from 'react'
import {NavLink} from 'react-router-dom'

export default class MyNavLink extends Component {
	render() {
		// console.log(this.props);
		return (
			<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}/>
		)
	}
}

5.配置路由

App.jsx

jsx 复制代码
import React, { Component } from 'react'
import { Route, Switch, Redirect } from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">

              {/* 原生html中,靠<a>跳转不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}

              {/* 在React中靠路由链接实现切换组件--编写路由链接 */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  <Redirect to="/about" />
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

入口文件:index.js

js 复制代码
//引入react核心库
import React from 'react'
//引入react-dom
import ReactDOM from 'react-dom/client'
//引入路由组件
import { BrowserRouter } from 'react-router-dom'
//引入App组件
import App from './App'

//渲染App组件到页面
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

想要练习的jym可以私我要css代码

效果展示:

6.路由的严格匹配与模糊匹配

  1. 默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
  2. 开启严格匹配:<Route exact={true} path="/about" component={About}/>
  3. 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

7.Redirect的使用(兜底)

  1. 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由.
  2. 具体编码:
js 复制代码
<Switch>
	<Route path="/about" component={About}/>
	<Route path="/home" component={Home}/>
	<Redirect to="/about"/>
</Switch>

四、速通嵌套路由

嵌套路由就是在组件内部定义子路由。在上面路由系统的基础上,在Home组件下创建子路由Message和News.

Messages/index.jsx

jsx 复制代码
import React, { Component } from 'react'

export default class Message extends Component {
	render() {
	   return (
	     <div>
		<ul>
		  <li>
	            <a href="/message1">message001</a>&nbsp;&nbsp;
		  </li>
		  <li>
		    <a href="/message2">message002</a>&nbsp;&nbsp;
		  </li>
		  <li>
		    <a href="/message/3">message003</a>&nbsp;&nbsp;
		  </li>
	        </ul>
	     </div>
	   )
	}
}

News/index.jsx

jsx 复制代码
import React, { Component } from 'react'

export default class News extends Component {
	render() {
	   return (
		<ul>
	           <li>news001</li>
		   <li>news002</li>
		   <li>news003</li>
		</ul>
	   )
   }
}

在Home组件下注册子路由

jsx 复制代码
import React, { Component } from 'react'
import MyNavLink from '../../components/MyNavLink'
import {Route,Switch,Redirect} from 'react-router-dom'
import News from './News'
import Message from './Message'

export default class Home extends Component {
	render() {
	   return (
		<div>
		   <h3>我是Home的内容</h3>
		   <div>
		     <ul className="nav nav-tabs">
			<li>
			  <MyNavLink to="/home/news">News</MyNavLink>
			</li>
			<li>
			  <MyNavLink to="/home/message">Message</MyNavLink>
			</li>
		     </ul>
		     {/* 注册路由 */}
		     <Switch>
			<Route path="/home/news" component={News}/>
			<Route path="/home/message" component={Message}/>
			<Redirect to="/home/news"/>
		     </Switch>
		   </div>
		</div>
	   )
	}
}

效果展示:

五、React Router 的最佳实践

1. 使用 Hooks

React Router v5.1 引入了 Hooks,能够更方便地获取路由信息:

jsx 复制代码
import { useParams, useHistory } from 'react-router-dom';

const User = () => {
  const { id } = useParams();
  const history = useHistory();

  return (
    <div>
      <h1>用户ID: {id}</h1>
      <button onClick={() => history.goBack()}>返回</button>
    </div>
  );
};

2. 延迟加载组件

延迟加载组件可以提高应用的加载速度:

jsx 复制代码
import { lazy, Suspense } from 'react';

const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>加载中...</div>}>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
        </Switch>
      </Suspense>
    </Router>
  );
}

总结

React Router 为 React 应用提供了强大且灵活的路由解决方案,无论是简单的单页应用,还是复杂的企业级应用,它都能很好地满足需求。通过本文的介绍,你已经了解了 React Router 的基本概念、核心组件、使用方法、进阶应用以及最佳实践。希望这些内容能够帮助你在开发 React 应用时更加高效地管理路由。

经典面试题

React Router v6的loader函数与自定义守卫组件在性能上有何差异?

回答:

⚙️ 1. 执行时机与渲染流程

(1)loader函数

○ 时机:在路由匹配后、组件渲染前执行,属于路由层拦截

○ 优势:

  • 并行加载:多个路由的loader可并行执行,避免组件层级的"请求瀑布流"(Network Waterfalls)

  • 无冗余渲染:若loader中重定向(如redirect('/login')),直接中断渲染流程,不会触发组件生命周期

○ 性能影响:减少不必要的组件挂载和卸载开销,适合深层嵌套路由的权限校验

(2) 自定义守卫组件

○ 时机:在组件渲染阶段执行(如useEffect或渲染逻辑中),属于组件层拦截

○ 劣势:

  • 组件需先渲染:即使权限校验失败,守卫组件及其子组件仍会经历挂载→校验→跳转的过程,可能触发多次状态更新

  • 串行请求:若父子路由均需权限校验,请求会按层级顺序执行,延长整体加载时间

⚡ 2. 数据预加载与用户体验

(1) loader函数

○ 数据预加载:可在权限校验时同步预加载页面数据,通过useLoaderData直接传递至组件,避免二次请求

○ 用户体验优化:

  • 结合Suspense展示全局加载状态,减少页面闪烁

  • 支持缓存策略(如内存缓存),避免重复请求相同数据

(2)自定义守卫组件

○ 数据分离:权限校验与数据加载逻辑分离,需在组件内单独处理数据请求,易导致加载状态分散(如多个loading提示)

○ 白屏风险:若权限校验后需加载数据,用户可能经历"校验→跳转→数据加载→渲染"的流程,增加等待时间

🛡️ 3. 错误处理效率

(1) loader函数

○ 统一错误处理:通过errorElement集中处理loader抛出的异常(如401重定向),减少冗余代码

○ 错误边界清晰:错误仅影响当前路由子树,不影响全局布局

(2) 自定义守卫组件

○ 分散处理:需在每个守卫组件内单独处理错误(如try/catch),代码重复率高

○ 易遗漏:可能忘记处理异步校验的异常,导致页面卡死

相关推荐
i听风逝夜22 分钟前
Web 3D地球实时统计访问来源
前端·后端
iMonster27 分钟前
React 组件的组合模式之道 (Composition Pattern)
前端
呐呐呐呐呢35 分钟前
antd渐变色边框按钮
前端
元直数字电路验证1 小时前
Jakarta EE Web 聊天室技术梳理
前端
wadesir1 小时前
Nginx配置文件CPU优化(从零开始提升Web服务器性能)
服务器·前端·nginx
牧码岛1 小时前
Web前端之canvas实现图片融合与清晰度介绍、合并
前端·javascript·css·html·web·canvas·web前端
灵犀坠1 小时前
前端面试八股复习心得
开发语言·前端·javascript
9***Y481 小时前
前端动画性能优化
前端
网络点点滴1 小时前
Vue3嵌套路由
前端·javascript·vue.js
牧码岛1 小时前
Web前端之Vue+Element打印时输入值没有及时更新dom的问题
前端·javascript·html·web·web前端