前言
在现代Web开发中,React凭借其高效的组件化开发模式和虚拟DOM技术,已成为构建用户界面的首选库之一。然而,仅掌握React的核心概念并不足以应对复杂的单页应用(SPA)开发需求。路由管理作为连接各个页面、实现视图切换的关键环节,对于提供流畅的用户体验至关重要。无论是导航到不同的页面,还是根据URL动态展示内容,合理设计与实现路由都是每个React开发者必须面对的课题。
本文旨在为读者提供一个全面而深入的指南,帮助你从基础到高级全面掌握React路由的应用。无论你是刚刚接触React的新手,还是希望进一步提升技能的有经验开发者,“React 路由:一篇就够了”都将为你揭开React路由管理的神秘面纱。我们将从最基础的路由配置开始,逐步深入探讨如何利用react-router-dom
库进行页面导航、参数传递、嵌套路由设置,乃至基于权限控制的私有路由实现等高级话题。此外,我们还将介绍懒加载等优化策略,以提高应用性能。通过阅读这篇文章,你将能够自信地在自己的项目中实现高效且灵活的路由系统,让开发过程更加得心应手。让我们一起开启这段探索React路由之旅吧!
安装 react-router-dom
yarn add react-router-dom
或者npm install react-router-dom
路由引入
在App.tsx里引入
import './App.css'
import AppRoutes from './routes/RouterConfig'
const App: React.FC = () => {
return (
<div className="App">
<AppRoutes />
</div>
)
}
export default App
路由配置
下面的是路由的配置, 这里使用的是基于history模式的BrowserRouter,当然也可以使用HashRouter包裹(哈希路由)。
这里也配置了二级路由,同时也加了路由守卫
import { FC } from 'react'
import { BrowserRouter, Route, Routes, Outlet } from 'react-router-dom'
import Login from '@/pages/LoginPage'
import Home from '@/pages/Home'
import About from '@/pages/About'
import NotFoundPage from '@/pages/NotFoundPage'
import PrivateRoute from './PrivateRoute'
export const routes = [
{ path: '/login', element: <Login />, isPrivate: false },
{ path: '/', element: <Home />, isPrivate: true, children: [{ path: 'about', element: <About />, isPrivate: true }] },
{ path: '*', element: <NotFoundPage />, isPrivate: false },
]
const AppRoutes: FC = () => {
// 递归渲染路由
const renderRoutes = (routes: any) => {
return routes.map((route: any) => {
let element = route.isPrivate ? <PrivateRoute>{route.element}</PrivateRoute> : route.element
if (route.children) {
element = (
<>
{element}
<Outlet />
</>
)
}
return (
<Route key={route.path} path={route.path} element={element}>
{route.children && renderRoutes(route.children)}
</Route>
)
})
}
return (
<BrowserRouter>
<Routes>{renderRoutes(routes)}</Routes>
</BrowserRouter>
)
}
export default AppRoutes
路由守卫
React的路由守卫(Route Guards)是一种用于控制页面访问的机制。它允许你在用户尝试访问某个页面之前,执行一些逻辑,如验证用户身份、检查页面权限等。
import { Navigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { RootState } from '@/store/index'
interface PrivateRouteProps {
children: JSX.Element
}
// 定义一个私有路由组件
const PrivateRoute: React.FC<PrivateRouteProps> = ({ children }) => {
// 从Redux中获取用户是否登录的状态
const isLoggedIn = useSelector((state: RootState) => state.authReducer.isLoggedIn)
// 如果用户已登录,则渲染子组件,否则重定向到登录页面
return isLoggedIn ? children : <Navigate to="/login" />
}
export default PrivateRoute
路由懒加载
使用懒加载lazy和当网络异常时的回调组件方式Suspense
下面是完整的路由配置代码
import { FC, lazy, Suspense } from 'react'
import { BrowserRouter, Route, Routes, Outlet } from 'react-router-dom'
import PrivateRoute from './PrivateRoute'
// 使用 lazy 函数进行懒加载
const Login = lazy(() => import('@/pages/LoginPage'))
const Home = lazy(() => import('@/pages/Home'))
const About = lazy(() => import('@/pages/About'))
const NotFoundPage = lazy(() => import('@/pages/NotFoundPage'))
export const routes = [
{ path: '/login', element: <Login />, isPrivate: false },
{ path: '/', element: <Home />, isPrivate: true, children: [{ path: 'about', element: <About />, isPrivate: true }] },
{ path: '*', element: <NotFoundPage />, isPrivate: false },
]
const AppRoutes: FC = () => {
const renderRoutes = (routes: any) => {
return routes.map((route: any) => {
let element = route.isPrivate ? <PrivateRoute>{route.element}</PrivateRoute> : route.element
if (route.children) {
element = (
<>
{element}
<Outlet />
</>
)
}
return (
<Route key={route.path} path={route.path} element={<Suspense fallback={<div>加载中……</div>}>{element}</Suspense>}>
{route.children && renderRoutes(route.children)}
</Route>
)
})
}
return (
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Routes>{renderRoutes(routes)}</Routes>
</Suspense>
</BrowserRouter>
)
}
export default AppRoutes
react-router-dom 基本原理
在React应用中,路由跳转的原理主要依赖于react-router-dom
库所提供的机制。该库基于HTML5 History API(包括pushState
、replaceState
等方法)和哈希(hash)模式来管理URL的变化,并通过监听URL变化来动态加载不同的组件,从而实现页面的无刷新切换。以下是React路由跳转的基本原理及其工作流程:
基本原理
-
History API:
react-router-dom
使用了HTML5的History API来操作浏览器的历史记录栈。这意味着它可以添加或修改历史记录条目,使得用户可以通过前进或后退按钮导航,而不会触发整个页面的重新加载。具体来说,当进行路由跳转时,它会调用history.push()
或history.replace()
等方法来改变当前的URL路径。 -
监听URL变化: 当用户执行某些动作(如点击链接或浏览器的前进/后退按钮)导致URL发生变化时,
react-router-dom
会监听到这些变化。这通常通过window
对象上的popstate
事件来实现。一旦检测到URL变化,它就会根据新的URL路径来决定应该渲染哪个组件。 -
匹配路由与渲染组件: 根据配置好的路由表,
react-router-dom
会尝试将当前的URL路径与定义的路由进行匹配。如果找到匹配项,则会渲染相应的React组件;如果没有匹配项,则可能会显示404页面或其他默认内容
工作流程
-
初始化: 在应用启动时,
react-router-dom
会首先读取配置好的路由表,并根据初始URL渲染对应的组件。 -
导航跳转: 当需要从一个页面跳转到另一个页面时,可以使用
<Link>
组件或者编程方式(如useNavigate
钩子)来发起跳转。这会导致URL发生变化,但不会重新加载整个页面。 -
响应URL变化: URL更新后,
react-router-dom
会监听到这一变化,并查找与新URL相匹配的路由规则。如果找到了匹配项,就渲染对应的组件;否则,可能展示一个错误页面。 -
状态管理: 除了基本的路由跳转外,
react-router-dom
还允许你在跳转过程中传递状态信息,比如通过查询参数或者路由状态等。