说说你对 React Router 的理解?常用的 Router 组件有哪些?
问题解析(面试官考察点)
面试官通过此问题主要考察:
- 对前端路由概念的理解程度
- 对 React Router 核心功能的掌握
- 对常用 Router 组件的熟悉程度和使用场景
- 对单页应用(SPA)路由机制的理解
核心概念(基础知识点)
什么是 React Router
React Router 是 React 生态系统中用于实现路由功能的库,它可以在不刷新页面的情况下,根据 URL 的变化来切换显示不同的组件内容,实现单页应用(SPA)的页面导航。
React Router 的核心包
- react-router: 实现了路由的核心功能
- react-router-dom: 基于 react-router,加入了在浏览器运行环境下的功能
- react-router-native: 基于 react-router,加入了 react-native 运行环境下的功能
- react-router-config: 用于配置静态路由的工具库
详细解答(代码示例)
常用的 Router 组件
1. BrowserRouter / HashRouter
作为路由的容器组件,包裹整个应用:
import { BrowserRouter as Router } from "react-router-dom";
function App() {
return (
<Router>
<main>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</main>
</Router>
);
}
2. Route 组件
用于路径匹配和组件渲染:
import { BrowserRouter as Router, Route } from "react-router-dom";
function App() {
return (
<Router>
<main>
{/* 使用 component 属性 */}
<Route path="/" exact component={Home} />
{/* 使用 render 属性 */}
<Route path="/welcome" render={() => <h1>Welcome!</h1>} />
{/* 使用 children 属性 */}
<Route path="/dashboard">
<Dashboard />
</Route>
</main>
</Router>
);
}
Route 组件常用属性:
path: 匹配的路径component: 匹配成功后渲染的组件render: 匹配成功后渲染的内容(函数形式)exact: 开启精确匹配
3. Link / NavLink 组件
用于页面跳转,替代传统的 <a> 标签:
import { Link, NavLink } from "react-router-dom";
function Navigation() {
return (
<nav>
{/* 基础链接 */}
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
{/* 带活跃样式的链接 */}
<NavLink to="/" exact activeStyle={{ color: "red" }}>
首页
</NavLink>
<NavLink to="/about" activeClassName="active">
关于
</NavLink>
</nav>
);
}
4. Switch 组件
用于包裹多个 Route,只渲染第一个匹配的组件:
import { Switch, Route } from "react-router-dom";
function App() {
return (
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/profile" component={Profile} />
<Route path="/:userid" component={User} />
<Route component={NoMatch} /> {/* 404 页面 */}
</Switch>
);
}
5. Redirect 组件
用于路由重定向:
import { Redirect } from "react-router-dom";
function About({ match: { params: { name } } }) {
return (
<>
{name !== "tom" ? <Redirect to="/" /> : null}
<h1>About {name}</h1>
</>
);
}
6. Hooks API
React Router v5+ 提供的 Hooks:
import { useHistory, useParams, useLocation } from "react-router-dom";
function Contact() {
const history = useHistory();
const { id } = useParams();
const { pathname } = useLocation();
return (
<div>
<h1>Contact</h1>
<p>Current URL: {pathname}</p>
<p>ID: {id}</p>
<button onClick={() => history.push("/")}>
Go to home
</button>
<button onClick={() => history.goBack()}>
Go back
</button>
</div>
);
}
参数传递方式
动态路由参数
// 定义路由
<Route path="/detail/:id" component={Detail}/>
// 获取参数
function Detail({ match }) {
const { id } = match.params;
return <div>Detail ID: {id}</div>;
}
// 或使用 useParams
import { useParams } from "react-router-dom";
function Detail() {
const { id } = useParams();
return <div>Detail ID: {id}</div>;
}
Query 参数
// 跳转时传递
<Link to="/detail?name=why&age=18">详情</Link>
// 获取参数
import { useLocation } from "react-router-dom";
function Detail() {
const location = useLocation();
const searchParams = new URLSearchParams(location.search);
const name = searchParams.get("name");
const age = searchParams.get("age");
return <div>Name: {name}, Age: {age}</div>;
}
State 传参
// 跳转时传递
<Link to={{
pathname: "/detail",
state: { name: "kobe", age: 30 }
}}>详情</Link>
// 获取参数
import { useLocation } from "react-router-dom";
function Detail() {
const location = useLocation();
const { name, age } = location.state || {};
return <div>Name: {name}, Age: {age}</div>;
}
深入理解(原理剖析)
前端路由的本质
前端路由的本质是 URL 与 UI 之间的映射关系。当 URL 发生变化时,页面的显示结果根据 URL 的变化而变化,但页面不会刷新。
React Router 的工作原理
-
History 管理: React Router 通过封装浏览器原生的 History API(history 模式)或监听 hashchange 事件(hash 模式)来管理 URL 变化
-
Context 传递: Router 组件通过 React Context 将 location、history 等数据传递给子组件
-
路径匹配: Route 组件通过 path-to-regexp 等库将当前路径与配置的 path 进行匹配
-
组件渲染: 匹配成功后,渲染对应的组件内容
HashRouter vs BrowserRouter
| 特性 | HashRouter | BrowserRouter |
|---|---|---|
| URL 形式 | /#/path |
/path |
| 实现原理 | hashchange 事件 | History API |
| 兼容性 | 更好(IE8+) | 现代浏览器 |
| 服务端配置 | 不需要 | 需要配置 fallback |
| SEO | 较差 | 较好 |
最佳实践
1. 路由配置抽离
// routes.js
const routes = [
{ path: "/", exact: true, component: Home },
{ path: "/about", component: About },
{ path: "/users/:id", component: User },
{ component: NotFound }
];
// App.js
import { Route, Switch } from "react-router-dom";
import routes from "./routes";
function App() {
return (
<Switch>
{routes.map((route, index) => (
<Route key={index} {...route} />
))}
</Switch>
);
}
2. 路由懒加载
import { lazy, Suspense } from "react";
import { Route, Switch } from "react-router-dom";
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
);
}
3. 路由守卫实现
import { Route, Redirect } from "react-router-dom";
function PrivateRoute({ component: Component, isAuth, ...rest }) {
return (
<Route
{...rest}
render={(props) =>
isAuth ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/login", state: { from: props.location } }} />
)
}
/>
);
}
4. 使用 useHistory 替代 withRouter
// 推荐:使用 Hooks
import { useHistory } from "react-router-dom";
function MyComponent() {
const history = useHistory();
const handleClick = () => {
history.push("/target");
};
return <button onClick={handleClick}>Go</button>;
}
面试要点
-
React Router 是什么: 用于 React 应用的路由管理库,实现 SPA 无刷新页面切换
-
常用组件:
BrowserRouter/HashRouter: 路由容器Route: 路径匹配和组件渲染Link/NavLink: 导航链接Switch: 只渲染第一个匹配的 RouteRedirect: 重定向
-
Hooks API:
useHistory: 获取 history 对象useParams: 获取路由参数useLocation: 获取当前 location
-
两种模式区别:
- Hash 模式使用 URL hash,兼容性更好
- History 模式使用 History API,URL 更美观,需要服务端配置
-
参数传递: 动态路由参数、Query 参数、State 参数