React Router 的 Hooks

Avatar of Agney Menon
Agney Menon

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

React Router 5 充分利用了 hooks 的强大功能,并引入了四个不同的 hooks 来帮助进行路由。 如果你正在寻找 React Router 新模式的快速入门指南,你会发现这篇文章很有用。 但在我们了解 hooks 之前,我们将从一个新的路由渲染模式开始。

React Router 5 之前

// When you wanted to render the route and get router props for component
<Route path="/" component={Home} />


// Or when you wanted to pass extra props
<Route path="/" render={({ match }) => <Profile match={match} mine={true} />}>

使用 component 语法时,路由 props(matchlocationhistory)会隐式地传递给组件。 但是,一旦你需要将额外的 props 传递给组件,就必须将其更改为 render。 请注意,向 component 语法添加内联函数会导致组件在每次渲染时重新挂载。

React Router 5 之后

<Route path="/">
  <Home />
</Route>

请注意,没有将任何 props 隐式传递给 Home 组件。 但无需更改 Route 本身,你可以向 Home 组件添加任何额外的 props。 你不再会犯在每次渲染时重新挂载组件的错误,这是最好的 API。

但是现在路由 props 没有被隐式传递,那么我们如何访问 matchhistorylocation 呢? 我们是否必须用 withRouter 包装所有组件? 这就是 hooks 发挥作用的地方。

请注意,hooks 是在 React 16.8 版本中引入的,因此你需要使用高于该版本的 React 来使用它们。

useHistory

  • 提供对 React Router 中 history prop 的访问。
  • 指的是路由器使用的 history 包 依赖项。
  • 主要用例是使用函数(如 pushreplace 等)进行编程路由。
import { useHistory } from 'react-router-dom';

function Home() {
  const history = useHistory();
  return <button onClick={() => history.push('/profile')}>Profile</button>;
}

useLocation

  • 提供对 React Router 中 location prop 的访问。
  • 它类似于浏览器本身中的 window.location,但它在任何地方都可访问,因为它表示路由器状态和位置。
  • 此功能的主要用例是访问查询参数或完整的路由字符串。
import { useLocation } from 'react-router-dom';

function Profile() {
  const location = useLocation();
  useEffect(() => {
    const currentPath = location.pathname;
    const searchParams = new URLSearchParams(location.search);
  }, [location]);
  return <p>Profile</p>;
}

由于 location 属性是不可变的,因此 useEffect 会在每次路由更改时调用该函数,使其非常适合操作搜索参数或当前路径。

useParams

  • 提供对 URL 中搜索参数的访问。
  • 以前只能使用 match.params 来实现这一点。
import { useParams, Route } from 'react-router-dom';

function Profile() {
  const { name } = useParams();
  return <p>{name}'s Profile</p>;
}

function Dashboard() {
  return (
    <>
      <nav>
        <Link to={`/profile/ann`}>Ann's Profile</Link>
      </nav>
      <main>
        <Route path="/profile/:name">
          <Profile />
        </Route>
      </main>
    </>
  );
}

useRouteMatch

  • 提供对 match 对象的访问。
  • 如果它不带任何参数提供,它将返回组件或其父组件中最接近的匹配项。
  • 主要用例是构建嵌套路径。
import { useRouteMatch, Route } from 'react-router-dom';

function Auth() {
  const match = useRouteMatch();
  return (
    <>
      <Route path={`${match.url}/login`}>
        <Login />
      </Route>
      <Route path={`${match.url}/register`}>
        <Register />
      </Route>
    </>
  );
}

你还可以使用 useRouteMatch 在不渲染 Route 的情况下访问匹配项。 这是通过将 location 参数传递给它来完成的。

例如,假设你需要在 /profile 处渲染你自己的个人资料,如果 URL 包含该人的姓名 /profile/dan/profile/ann,则渲染其他人的个人资料。 在不使用 hook 的情况下,你将要么编写一个 Switch,列出两个路由并使用 props 自定义它们。 但现在,使用 hook,我们可以这样做

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

function Profile() {
  const match = useRouteMatch('/profile/:name');

  return match ? <p>{match.params.name}'s Profile</p> : <p>My own profile</p>;
}

export default function App() {
  return (
    <Router>
      <nav>
        <Link to="/profile">My Profile</Link>
        <br />
        <Link to={`/profile/ann`}>Ann's Profile</Link>
      </nav>
      <Route path="/profile">
        <Profile />
      </Route>
    </Router>
  );
}

你还可以将 Route 上的所有 props(如 exactsensitive)作为对象与 useRouteMatch 一起使用。

总结

hooks 和显式的 Route 本身就具有一个隐藏的优势。 在多个研讨会上教授了这些技巧之后,我意识到这些技巧有助于避免早期模式带来的许多困惑和复杂性。 突然之间,非强制性错误要少得多。 它们肯定会帮助你使路由器代码更易于维护,并且你会发现升级到新的 React Router 版本变得更容易。