Skip to content

React Router

1. 什么是 React Router?它的主要作用是什么?

答案:React Router 是 React 生态系统中最常用的路由库。它允许你在 React 应用中实现动态路由,使得单页应用 (SPA) 能够像多页应用一样工作,而无需重新加载页面。

主要作用:

  1. 声明式路由定义
  2. 动态路由匹配
  3. 嵌套路由和布局
  4. 历史管理
  5. 代码分割

2. React Router 的基本组件有哪些?它们的作用是什么?

答案:React Router 的基本组件包括:

  1. <BrowserRouter>:使用 HTML5 history API 来保持 UI 和 URL 的同步。
  2. <Route>:定义路由路径和要渲染的组件。
  3. <Link>:声明式的导航组件,用于创建链接。
  4. <Switch>:渲染第一个匹配的 <Route><Redirect>
  5. <Redirect>:强制导航到特定位置。

示例:

jsx
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <Link to="/">Home</Link>
          <Link to="/about">About</Link>
        </nav>

        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Redirect to="/" />
        </Switch>
      </div>
    </Router>
  );
}

3. 如何在 React Router 中实现动态路由?

答案:动态路由可以通过在路径中使用参数来实现。这些参数可以在组件中通过 props 访问。

示例:

jsx
import { BrowserRouter as Router, Route, useParams } from 'react-router-dom';

function UserProfile() {
  let { id } = useParams();
  return <div>User ID: {id}</div>;
}

function App() {
  return (
    <Router>
      <Route path="/user/:id" component={UserProfile} />
    </Router>
  );
}

在这个例子中,/user/123 这样的 URL 会匹配 UserProfile 组件,并且 123 会作为 id 参数传递给组件。

答案<Link> 组件和 <a> 标签的主要区别在于:

  1. <Link> 使用 React Router 的内部机制来处理导航,不会导致整个页面重新加载。
  2. <Link> 会阻止默认的页面刷新行为,而是使用 History API 来更新 URL。
  3. <Link> 可以感知和利用 React Router 的上下文。

示例:

jsx
import { Link } from 'react-router-dom';

function Navigation() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
    </nav>
  );
}

5. 如何在 React Router 中实现路由守卫(Route Guards)?

答案:React Router 没有内置的路由守卫机制,但我们可以通过创建自定义组件来实现类似的功能。

示例:

jsx
import { Route, Redirect } from 'react-router-dom';

function PrivateRoute({ component: Component, isAuthenticated, ...rest }) {
  return (
    <Route
      {...rest}
      render={(props) =>
        isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect to="/login" />
        )
      }
    />
  );
}

function App() {
  const isAuthenticated = checkAuthStatus(); // 假设这个函数检查认证状态

  return (
    <Router>
      <Switch>
        <Route path="/login" component={Login} />
        <PrivateRoute
          path="/dashboard"
          component={Dashboard}
          isAuthenticated={isAuthenticated}
        />
      </Switch>
    </Router>
  );
}

这个例子中的 PrivateRoute 组件会检查用户是否已认证,如果没有,则重定向到登录页面。

6. 什么是编程式导航?如何在 React Router 中实现?

答案:编程式导航是指通过 JavaScript 代码来控制路由跳转,而不是通过点击链接。在 React Router 中,我们可以使用 history 对象来实现编程式导航。

示例:

jsx
import { useHistory } from 'react-router-dom';

function NavigateButton() {
  let history = useHistory();

  function handleClick() {
    history.push('/home');
  }

  return (
    <button type="button" onClick={handleClick}>
      Go to Home
    </button>
  );
}

在这个例子中,点击按钮会导航到 '/home' 路径。

7. 如何在 React Router 中实现嵌套路由?

答案:嵌套路由可以通过在父路由组件中定义子路由来实现。

示例:

jsx
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';

function User() {
  return (
    <div>
      <h2>User</h2>
      <nav>
        <Link to="/user/profile">Profile</Link>
        <Link to="/user/settings">Settings</Link>
      </nav>

      <Switch>
        <Route path="/user/profile" component={Profile} />
        <Route path="/user/settings" component={Settings} />
      </Switch>
    </div>
  );
}

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/user" component={User} />
        <Route path="/" exact component={Home} />
      </Switch>
    </Router>
  );
}

在这个例子中,/user/profile/user/settings/user 的子路由。

8. 什么是 React Router 的 withRouter 高阶组件?它有什么用途?

答案withRouter 是一个高阶组件,它可以将 React Router 的 historylocationmatch 对象作为 props 传递给被包装的组件。这对于需要访问路由信息但不直接在路由中渲染的组件很有用。

示例:

jsx
import { withRouter } from 'react-router-dom';

function MyComponent({ history, location, match }) {
  return (
    <div>
      <p>Current path: {location.pathname}</p>
      <button onClick={() => history.push('/home')}>Go to Home</button>
    </div>
  );
}

export default withRouter(MyComponent);

注意:在 React Router v6 中,withRouter 被移除,推荐使用 hooks 如 useHistoryuseLocationuseParams 来替代。

9. React Router 中的 <Switch> 组件有什么作用?

答案<Switch> 组件用于渲染与当前位置匹配的第一个 <Route><Redirect>。这对于排他性路由很有用,确保只渲染一个路由。

没有 <Switch> 的情况下,所有匹配的路由都会被渲染。使用 <Switch> 可以提高路由的效率和可预测性。

示例:

jsx
import { Switch, Route } from 'react-router-dom';

function App() {
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/:user" component={User} />
      <Route component={NoMatch} />
    </Switch>
  );
}

在这个例子中,只有一个路由会被渲染,而且 /:user 不会匹配 /about

10. 如何在 React Router 中实现路由的懒加载?

答案:路由的懒加载可以通过 React 的 lazySuspense 功能结合 React Router 来实现。这可以显著提高应用的性能,特别是对于大型应用。

示例:

jsx
import React, { lazy, Suspense } 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>
  );
}

在这个例子中,HomeAbout 组件会在需要时才被加载,而不是在应用启动时就全部加载。Suspense 组件提供了一个加载指示器,在组件加载完成之前显示。