一、安装与基本结构

1
npm install react-router-dom

React Router 6 推荐的 API 是 createBrowserRouter(数据路由),路由配置集中管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// main.jsx
import { createRoot } from 'react-dom/client'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import Layout from './Layout'
import Home from './pages/Home'
import About from './pages/About'
import NotFound from './pages/NotFound'

const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{ index: true, element: <Home /> },
{ path: 'about', element: <About /> },
{ path: '*', element: <NotFound /> }
]
}
])

createRoot(document.getElementById('root')).render(
<RouterProvider router={router} />
)

关键点:

  • 嵌套路由:Layout 作为父路由,用 <Outlet /> 渲染子路由;
  • index: true:父路径的默认子路由(访问 / 时渲染 Home);
  • *:通配符兜底 404。

二、Layout 与 Outlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Layout.jsx
import { Outlet, NavLink } from 'react-router-dom'

export default function Layout() {
return (
<div>
<nav>
{/* NavLink 自动处理激活态 */}
<NavLink
to="/"
className={({ isActive }) => (isActive ? 'active' : '')}
end // end 让首页只在完全匹配时高亮
>
首页
</NavLink>
<NavLink to="/about">关于</NavLink>
</nav>

{/* 子路由渲染的位置 */}
<Outlet />
</div>
)
}

三、编程式导航与传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'

function UserDetail() {
const navigate = useNavigate()
const { id } = useParams() // 路径参数:/user/123 → id=123
const [searchParams, setSearchParams] = useSearchParams()

const page = searchParams.get('page') || '1' // ?page=2

return (
<div>
<p>用户:{id},页码:{page}</p>
<button onClick={() => setSearchParams({ page: '3' })}>下一页</button>
<button onClick={() => navigate('/')}>回首页</button>
</div>
)
}

四、路由守卫:未登录跳登录页

数据路由里可以用 loader + 重定向做守卫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { redirect } from 'react-router-dom'

// 守卫逻辑
function requireAuth() {
const token = localStorage.getItem('token')
if (!token) {
// 重定向到登录页,并记录来源
return redirect(`/login?redirect=${encodeURIComponent(location.pathname)}`)
}
return null
}

const router = createBrowserRouter([
{
path: '/dashboard',
loader: requireAuth, // 进入前先执行
element: <Dashboard />
}
])

或者更直观的组件式守卫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function RequireAuth({ children }) {
const token = localStorage.getItem('token')
const location = useLocation()

if (!token) {
return <Navigate to="/login" replace state={{ from: location }} />
}
return children
}

// 使用
<Route
path="/dashboard"
element={
<RequireAuth>
<Dashboard />
</RequireAuth>
}
/>

五、懒加载与代码分割

React.lazy + Suspense 让路由级组件按需加载,首屏只下载必要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Suspense, lazy } from 'react'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'

// 每个页面独立 chunk
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
const Dashboard = lazy(() => import('./pages/Dashboard'))

const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{ index: true, element: <Home /> },
{ path: 'about', element: <About /> },
{ path: 'dashboard', element: <Dashboard /> }
]
}
])

// 包一层 Suspense 显示加载态
function App() {
return (
<Suspense fallback={<div>页面加载中...</div>}>
<RouterProvider router={router} />
</Suspense>
)
}

构建后看产物:每个路由页面对应一个独立 chunk,首屏只加载入口 + 首页。

六、错误边界:路由级容错

数据路由支持配置 errorElement,路由渲染或 loader 出错时展示错误页:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function ErrorPage() {
const error = useRouteError()
return (
<div>
<h1>出错了</h1>
<p>{error.status === 404 ? '页面不存在' : '加载失败,请刷新重试'}</p>
</div>
)
}

const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
errorElement: <ErrorPage />,
children: [/* ... */]
}
])

七、部署注意:SPA 刷新 404

React Router 用 history 模式,服务器必须把所有路径回退到 index.html:

1
2
3
4
# Nginx
location / {
try_files $uri $uri/ /index.html;
}

不然直接访问 /about 会 404。

常见坑

  1. NavLink 高亮错乱:忘记 end 属性,首页在任意路径都高亮;
  2. useParams 取不到值:确认路由路径写的是 :id 且当前路由确实匹配;
  3. 懒加载白屏:Suspense 没包住懒组件,或组件内部抛错,配合 errorElement 排查;
  4. 跳转后滚动位置不对:用 useScrollRestoration(数据路由内置)或自己监听。

总结

React Router 6 的实践核心:createBrowserRouter 集中配置 → 嵌套路由 + Outlet → 守卫(loader/组件式)→ lazy 分包 → errorElement 容错。这套组合能支撑中大型前端应用的导航和权限体系。