一、React Router 基础
1.1 安装 React Router
要在项目中使用 React Router,首先需要安装:
npm install react-router-dom
安装完成后,你可以在应用中使用 BrowserRouter
、Route
、Switch
等组件来实现路由功能。
1.2 基本路由配置
最简单的路由配置通常包含以下几个部分:
BrowserRouter
:用于包裹整个应用,提供路由功能。Route
:定义路径和对应的组件,当路径匹配时渲染对应组件。Switch
:确保一次只渲染一个路由。
代码如下:
import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function Home() { return <h2>Home</h2>; } function About() { return <h2>About</h2>; } function App() { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Switch> </Router> ); } export default App;
exact
:确保路径精确匹配,例如,只有当路径完全是'/'
时才会渲染Home
组件。
1.3 链接与导航
使用 Link
组件创建导航链接,它会渲染一个普通的 <a>
标签,但点击时不会触发页面刷新,而是通过 React Router
实现路由跳转。
import { Link } from 'react-router-dom'; function Navbar() { return ( <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> </ul> </nav> ); }
二、React Router 高级功能
2.1 动态路由
在实际开发中,经常需要基于动态参数来渲染组件,比如用户详情页。React Router 提供了动态路由功能,允许通过 URL 参数传递信息。
function User({ match }) { return <h2>User ID: {match.params.id}</h2>; } function App() { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/user/:id" component={User} /> </Switch> </Router> ); }
在上述代码中,:id
是一个动态参数,可以通过 match.params.id
访问它。
2.2 嵌套路由
嵌套路由允许你在一个组件内部定义子路由,从而实现模块化路由配置。
function Dashboard({ match }) { return ( <div> <h2>Dashboard</h2> <ul> <li> <Link to={`${match.url}/profile`}>Profile</Link> </li> <li> <Link to={`${match.url}/settings`}>Settings</Link> </li> </ul> <Route path={`${match.path}/profile`} component={Profile} /> <Route path={`${match.path}/settings`} component={Settings} /> </div> ); }
在这个例子中,Dashboard
组件内部的 Profile
和 Settings
都是子路由。
2.3 路由守卫
路由守卫用于控制路由的访问权限,例如,只有登录用户才能访问某些页面。React Router 提供了 Redirect
组件来实现这一功能。
function PrivateRoute({ component: Component, ...rest }) { const isAuthenticated = fakeAuth.isAuthenticated; // 示例中的认证逻辑 return ( <Route {...rest} render={props => isAuthenticated ? ( <Component {...props} /> ) : ( <Redirect to="/login" /> ) } /> ); } function App() { return ( <Router> <Switch> <Route path="/login" component={Login} /> <PrivateRoute path="/dashboard" component={Dashboard} /> </Switch> </Router> ); }
在这里,PrivateRoute
组件封装了访问权限的检查逻辑,如果用户未登录,将重定向到登录页面。
2.4 使用 useHistory
和 useLocation
Hooks
React Router 提供了 useHistory
和 useLocation
两个 Hooks,用于在函数组件中访问和控制路由历史记录和当前位置。
import { useHistory, useLocation } from 'react-router-dom'; function SomeComponent() { let history = useHistory(); let location = useLocation(); function goBack() { history.goBack(); // 返回上一页 } return ( <div> <p>Current location: {location.pathname}</p> <button onClick={goBack}>Go Back</button> </div> ); }
useHistory
:可以用来编程式导航(例如,history.push('/somepath')
)。useLocation
:可以访问当前的URL信息。
路由优化
4.1 懒加载路由
当应用变得复杂时,加载所有的组件可能会影响页面的加载速度。React 提供了 React.lazy
和 Suspense
进行组件的懒加载,可以与 React Router 结合,实现按需加载路由组件。
import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; const Home = lazy(() => import('./Home')); const About = lazy(() => import('./About')); function App() { return ( <Router> <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Switch> </Suspense> </Router> ); } export default App;
React.lazy
:将组件动态加载,只有在需要时才会加载对应的组件。Suspense
:用于在组件加载过程中显示一个备用内容(如加载动画)。
4.2 路由配置文件化
对于大型应用,路由配置可能会非常复杂,将路由配置文件化是一个良好的实践,能够提高路由的可维护性。
// routes.js import Home from './Home'; import About from './About'; const routes = [ { path: '/', exact: true, component: Home, }, { path: '/about', component: About, }, ]; export default routes; // App.js import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import routes from './routes'; function App() { return ( <Router> <Switch> {routes.map((route, index) => ( <Route key={index} path={route.path} exact={route.exact} component={route.component} /> ))} </Switch> </Router> ); } export default App;
这种做法将所有路由集中在一个配置文件中,便于管理和扩展,特别是在需要动态生成路由的情况下。
4.3 处理 404 页面
在单页应用中,处理未匹配的路径非常重要,以确保用户不会访问无效的页面。可以通过添加一个匹配所有路径的 Route
来实现 404 页面。
function NotFound() { return <h2>404 - Page Not Found</h2>; } function App() { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route component={NotFound} /> </Switch> </Router> ); } export default App;
在上面的代码中,如果没有匹配到其他路径,将会渲染 NotFound
组件。
4.4 路由的权限管理
对于需要权限控制的应用,可以在 PrivateRoute
组件中添加更多的逻辑,如角色检查、权限验证等。
function PrivateRoute({ component: Component, roles, ...rest }) { const isAuthenticated = fakeAuth.isAuthenticated; const userRole = fakeAuth.userRole; return ( <Route {...rest} render={(props) => isAuthenticated && roles.includes(userRole) ? ( <Component {...props} /> ) : ( <Redirect to="/unauthorized" /> ) } /> ); }
在这种情况下,可以基于用户角色或权限来决定是否允许访问某个路由。
4.5 路由过渡动画
为了提高用户体验,可以为路由切换添加过渡动画。可以借助 react-transition-group
或 framer-motion
等库来实现。
import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function App() { return ( <Router> <Route render={({ location }) => ( <TransitionGroup> <CSSTransition key={location.key} classNames="fade" timeout={300} > <Switch location={location}> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Switch> </CSSTransition> </TransitionGroup> )} /> </Router> ); } export default App;
通过 CSSTransition
和 TransitionGroup
可以为路由的进入和离开添加自定义动画。