33. 常用的 React 路由库?(React Router) 原理?
答案:
常用的 React 路由库:
1. React Router
- 最流行和官方推荐的路由库 - 支持浏览器、服务端和 React Native - 声明式路由定义 - 支持动态路由、嵌套路由、路由守卫等
2. Reach Router
- 已被 React Router 合并 - 更简洁的 API 设计 - 更好的可访问性支持
3. Next.js Router
- Next.js 内置的基于文件系统的路由 - 自动代码分割 - 支持静态生成和服务端渲染
4. Wouter
- 轻量级路由库(约 1.5KB) - 简单的 Hook-based API - 适合小型项目
React Router 原理详解:
1. 基本概念
import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/users">Users</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users" element={<Users />} />
</Routes>
</Router>
)
}
2. History API 原理
React Router 基于浏览器的 History API 实现,主要使用以下 API:
// 浏览器历史记录操作
history.pushState(state, title, url) // 添加新的历史记录
history.replaceState(state, title, url) // 替换当前历史记录
history.go(delta) // 前进或后退
history.back() // 后退
history.forward() // 前进
// 监听浏览器前进后退
window.addEventListener('popstate', (event) => {
// 处理路由变化
})
3. Router 组件类型
// BrowserRouter - 使用 HTML5 history API
import { BrowserRouter } from 'react-router-dom'
function App() {
return <BrowserRouter>{/* 路由配置 */}</BrowserRouter>
}
// HashRouter - 使用 URL hash
import { HashRouter } from 'react-router-dom'
function App() {
return <HashRouter>{/* 路由配置 */}</HashRouter>
}
// MemoryRouter - 在内存中管理历史记录
import { MemoryRouter } from 'react-router-dom'
function App() {
return <MemoryRouter>{/* 路由配置 */}</MemoryRouter>
}
4. 路由匹配原理
// 路由配置
;<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<Users />} />
<Route path="/users/:id" element={<User />} />
<Route path="/users/:id/posts/:postId" element={<UserPost />} />
<Route path="*" element={<NotFound />} />
</Routes>
// 路由匹配算法
function matchRoutes(routes, pathname) {
for (let route of routes) {
const match = matchPath(route.path, pathname)
if (match) {
return { route, match }
}
}
return null
}
// 路径匹配函数
function matchPath(pattern, pathname) {
const keys = []
const regex = pathToRegexp(pattern, keys)
const match = regex.exec(pathname)
if (!match) return null
const params = {}
keys.forEach((key, index) => {
params[key.name] = match[index + 1]
})
return { params, pathname, pattern }
}
5. 动态路由和参数
// 路由参数
function UserProfile() {
const { id } = useParams() // 获取 :id 参数
const location = useLocation() // 获取当前位置信息
const navigate = useNavigate() // 编程式导航
return (
<div>
<h1>User Profile: {id}</h1>
<button onClick={() => navigate('/users')}>Back to Users</button>
</div>
)
}
// 查询参数
function SearchResults() {
const [searchParams, setSearchParams] = useSearchParams()
const query = searchParams.get('q')
const page = searchParams.get('page') || '1'
const handleSearch = (newQuery) => {
setSearchParams({ q: newQuery, page: '1' })
}
return (
<div>
<h1>Search Results for: {query}</h1>
<p>Page: {page}</p>
</div>
)
}
6. 嵌套路由
// 嵌套路由配置
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="users" element={<Users />}>
<Route index element={<UsersList />} />
<Route path=":id" element={<UserProfile />} />
<Route path=":id/posts" element={<UserPosts />} />
</Route>
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</Router>
)
}
// Layout 组件
function Layout() {
return (
<div>
<header>Navigation</header>
<main>
<Outlet /> {/* 渲染子路由 */}
</main>
<footer>Footer</footer>
</div>
)
}
// Users 组件
function Users() {
return (
<div>
<h1>Users</h1>
<Outlet /> {/* 渲染子路由 */}
</div>
)
}
7. 路由守卫和权限控制
// 路由守卫组件
function ProtectedRoute({ children, redirectTo = '/login' }) {
const { user } = useAuth()
const location = useLocation()
if (!user) {
return <Navigate to={redirectTo} state={{ from: location }} replace />
}
return children
}
// 角色权限守卫
function RoleGuard({ children, requiredRole, fallback = <Unauthorized /> }) {
const { user } = useAuth()
if (!user || !user.roles.includes(requiredRole)) {
return fallback
}
return children
}
// 使用守卫
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
<Route
path="/admin"
element={
<ProtectedRoute>
<RoleGuard requiredRole="admin">
<AdminPanel />
</RoleGuard>
</ProtectedRoute>
}
/>
</Routes>
</Router>
)
}
8. 编程式导航
function NavigationExample() {
const navigate = useNavigate()
const location = useLocation()
const handleSubmit = async (formData) => {
try {
await submitData(formData)
// 导航到成功页面
navigate('/success', {
state: { message: 'Data submitted successfully' },
})
} catch (error) {
// 导航到错误页面
navigate('/error', {
state: { error: error.message },
})
}
}
const goBack = () => {
navigate(-1) // 返回上一页
}
const goHome = () => {
navigate('/', { replace: true }) // 替换当前历史记录
}
return (
<div>
<button onClick={goBack}>Go Back</button>
<button onClick={goHome}>Go Home</button>
<form onSubmit={handleSubmit}>{/* 表单内容 */}</form>
</div>
)
}
9. 数据加载和 Loader
// React Router v6.4+ 的数据加载
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
// 数据加载函数
async function userLoader({ params }) {
const user = await fetch(`/api/users/${params.id}`)
if (!user.ok) {
throw new Response('User not found', { status: 404 })
}
return user.json()
}
// 路由配置
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{
path: 'users/:id',
element: <UserProfile />,
loader: userLoader,
errorElement: <UserError />,
},
],
},
])
// 组件中使用数据
function UserProfile() {
const user = useLoaderData() // 获取 loader 加载的数据
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
)
}
// 应用根组件
function App() {
return <RouterProvider router={router} />
}
10. 代码分割和懒加载
import { lazy, Suspense } from 'react'
// 懒加载组件
const Dashboard = lazy(() => import('./Dashboard'))
const UserProfile = lazy(() => import('./UserProfile'))
const AdminPanel = lazy(() => import('./AdminPanel'))
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/users/:id" element={<UserProfile />} />
<Route path="/admin" element={<AdminPanel />} />
</Routes>
</Suspense>
</Router>
)
}
// 带有加载状态的组件
function LazyRoute({ children, fallback = <LoadingSpinner /> }) {
return <Suspense fallback={fallback}>{children}</Suspense>
}
11. 路由状态管理
// 自定义路由状态 Hook
function useRouteState() {
const location = useLocation()
const navigate = useNavigate()
const setRouteState = useCallback(
(state) => {
navigate(location.pathname, {
state: { ...location.state, ...state },
replace: true,
})
},
[location, navigate]
)
return [location.state, setRouteState]
}
// 使用路由状态
function UsersList() {
const [routeState, setRouteState] = useRouteState()
const [searchParams, setSearchParams] = useSearchParams()
const currentPage = parseInt(searchParams.get('page') || '1')
const searchQuery = searchParams.get('q') || ''
const handlePageChange = (page) => {
setSearchParams({ ...Object.fromEntries(searchParams), page })
}
const handleSearch = (query) => {
setSearchParams({ q: query, page: '1' })
}
return (
<div>
<SearchBox onSearch={handleSearch} value={searchQuery} />
<UserList page={currentPage} />
<Pagination current={currentPage} onChange={handlePageChange} />
</div>
)
}
12. 自定义 Router
// 简化版 Router 实现
class SimpleRouter {
constructor() {
this.routes = []
this.currentPath = window.location.pathname
// 监听浏览器前进后退
window.addEventListener('popstate', () => {
this.currentPath = window.location.pathname
this.render()
})
}
addRoute(path, component) {
this.routes.push({ path, component })
}
navigate(path) {
window.history.pushState({}, '', path)
this.currentPath = path
this.render()
}
render() {
const route = this.routes.find((route) => {
return this.matchPath(route.path, this.currentPath)
})
if (route) {
const container = document.getElementById('app')
container.innerHTML = route.component()
}
}
matchPath(pattern, path) {
// 简单的路径匹配逻辑
return pattern === path
}
}
// 使用自定义 Router
const router = new SimpleRouter()
router.addRoute('/', () => '<h1>Home</h1>')
router.addRoute('/about', () => '<h1>About</h1>')
router.render()
工作原理总结:
1. 历史记录管理
- 使用 History API 管理浏览器历史记录
- 监听 popstate 事件处理前进后退
- 通过 pushState 和 replaceState 更新 URL
2. 路由匹配
- 将路由配置转换为正则表达式 - 按优先级匹配当前路径 - 提取路径参数和查询参数
3. 组件渲染
- 根据匹配结果渲染对应组件 - 支持嵌套路由和组件组合 - 通过 Context 传递路由信息
4. 导航控制
- 提供声明式和编程式导航 - 支持路由守卫和权限控制 - 处理路由状态和数据传递
总结:
- React Router 是最主流的 React 路由解决方案 - 核心原理 基于 History API 和组件渲染 - 主要特性 包括动态路由、嵌套路由、路由守卫、数据加载等 - 性能优化 支持代码分割和懒加载 - 最佳实践 包括合理的路由设计、权限控制、状态管理等