关于react-router的一些小细节和易错点

这篇文章是为了分享一些关于React-Router中不太注意的细节。

整体写法

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

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        {/* A <Switch> looks through its children <Route>s and
            renders the first one that matches the current URL. */}
        <Switch>
          <Route exact path="/about">
            <About />
          </Route>
          <Route exact path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Users() {
  return <h2>Users</h2>;
}

我们来看几个重点:

  • Router一个项目里只能有一个
  • Switch的第一个Route是作为默认的Route
  • 一般Link和Switch都在一个div里面

易错点

这里的易错点是我在设置一个route的child route的时候发现的。在demo中我用user来作为parent route。
首先,现在的React-Router比较喜欢我们分开来处理parent route和child route。而不是把他们都写在一块。
因此我们可以这样写

function Users() {
  let { path, url } = useRouteMatch();
  return (
    <div>
    <h2>Users</h2>
    <ul>
      <li>
        <Link to="/users/rendering">Rendering with React</Link>
      </li>
      <li>
        <Link to={`${url}/components`}>Components</Link>
      </li>
      <li>
        <Link to={`${url}/props-v-state`}>Props v. State</Link>
      </li>
  </ul>
  <Switch>
    <Route exact path={path}>
      <h3>Please select a topic.</h3>
    </Route>
    <Route path={`${path}/:topicId`}>
        <h2>{topicId}
    </Route>
  </Switch>
</div>
}

这样我们就可以在User函数里面创建child route。但其实这样的话是无法正常显示出user的child route的,原因就在于我们把parent route的path设置成了exact。
因此我们需要把APP函数里面的<Route exact path="/users">改成<Route path="/users">

关于问题发生的原因exact的介绍

exact是Route下的一条属性,一般而言,react路由会匹配所有匹配到的路由组件,exact能够使得路由的匹配更严格一些。
exact的值为bool型,为true是表示严格匹配,为false时为正常匹配。

如在exact为true时,/link/是不匹配的,但是在false的情况下它们又是匹配的。
一个常用的场景是这样的:

<Route path='/' component={Home} /> 
<Route path='/page' component={Page}> 
//这种情况下,page页面永远展示的是Home组件。

所以我们经常添加exact来解决上述问题。

<Route exact path='/' component={Home} /> 
<Route path='/page' component={Page} />

出现上面的问题的原因是,路由在匹配的时候,比如我们现在访问/page/根目录是/page的子集, 所以导致匹配成功,也就是说,没有设置严格匹配,也就是exact = { true }的情况下,路由的子集也是符合匹配要求的。

接下来我们回到我们最开始的问题,那个问题的答案是:使用嵌套路由在父级不能用exact
因为当你匹配路由时路径加了子路由,导致父级路由路径不匹配从而父子组件都显示不了。
例如这个/users 使用了exact,当路径变为/users/rendering时是匹配不到/users的,这样的话就无法渲染到/users,因此也不会渲染到/users的子路由/users/rendering了。

阅读 96

推荐阅读