React Router and nested routes

avatar

原文imkev.dev/react-route… 由石欣翻译

React Router 和嵌套路由

在 Remix v1 公开发布后,嵌套路由成为了所有人都在谈论的话题,至少在我所处的互联网世界的小角落里是这样。但是什么是嵌套路由,它们为什么重要,以及如何在您的 React 应用程序中使用嵌套路由?

React Router

嵌套路由从很早就存在于 React Router 中,它最初被命名为 react-nested-router 。现在在版本 6 上,React Router 是最受欢迎的 React 包之一,在整篇文章中 React Router 也将用于演示嵌套路由的概念。包括 React Router v5 代码示例和演示,但在解释代码时,请参考 v6 版本。

 ## Nested routes

嵌套路由是页面布局中响应路由更改的区域。例如,在单页应用程序中,从一个 URL 导航到另一个 URL 时,不需要呈现整个页面,而只需呈现页面中依赖于该 URL 更改的那些区域。

image (4).png 在上面的线框中,当单击标题链接 (4) 时,将呈现主要内容 (1) 以显示此路由的内容,而标题保持不变。同样,当单击左侧导航链接 (2) 时,页面的内容部分 (3) 将更新以显示新内容,但页眉、页脚和导航菜单保持不变。

此布局可以通过多种方式实现。

 

export default function App() {
  return (
    <div className="app">
      <BrowserRouter>
        <Routes>
          <Route path="/catalog/:id" element={<Catalog />} />
          <Route path="/catalog" element={<Catalog />} />
          <Route path="/welcome" element={<Welcome />} />
          <Route index element={<Home />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

Flat ro平面路由结构 - v6 | 平面路由结构 - v5

在上面的平面结构中,我们在单个文件中声明了四个路由。 /catalog/:id 和 /catalog 将呈现包含左侧导航和内容区域的  组件。如果存在 :id 参数,则它将显示该 :id 的内容,否则将显示一些默认内容。 /welcome 显示欢迎消息,最终捕获全部路由显示主页,包括 <Header> 和 <Footer> 。

在不同路线之间导航将导致主部分 (1) 使用更新的内容呈现。这包括 <Header> 、 <Footer> 和 <Nav> - 即使它们没有更改。如果你使用过这个演示,你可能会觉得它运行良好,没有明显的错误。这种路由结构相当普遍,我个人在生产中多次遇到过它。但是,这种结构没有经过优化,当从一个 URL 导航到另一个 URL 时,CPU 正在做很多不需要的工作。在我们的示例中,这种开销可以忽略不计,但在更复杂的应用程序中,它可能会导致可见的卡顿并恶化用户体验。

为了使重新渲染更加明显,添加了以下代码片段,但最初将其注释掉。

  React.useLayoutEffect(() => {
    if (ref && ref.current) {
      ref.current.style = "background-color: #fa9a9a;";
      setTimeout(() => {
        ref.current.style = "background-color: none;";
      });
    }
  });

lets-get-nested

可以使用嵌套路由来优化上述路由结构,以避免呈现未更改的组件。作为默认规则,我们只想渲染已更改的内容。当用户单击左侧导航链接时,我们唯一要呈现的组件是内容部分。同样,当用户单击标题链接时,我们只呈现主要部分。

export default function App() {
  return (
    <div className="app">
      <BrowserRouter>
        <Routes>
          <Route path="/welcome" element={<Welcome />} />
          <Route path="*" element={
            <Header />
            <Routes>
              <Route path="/catalog/*" element={
                <div className="two-column" ref={ref}>
                  <Nav />
                  <div className="content">
                    <Routes>
                      <Route path=":id" element={<Content />} />
                      <Route
                        index
                        element={<p>Use the left nav to selet a catalog item</p>}
                      />
                    </Routes>
                  </div>
                </div>
              } />
              <Route index element={<Home />} />
            </Routes>
            <Footer />
          } />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

嵌套路由 (v6) | 嵌套路由 (v5)

我们现在有六条路线分布在三个级别上,而不是在一个级别上有三条路线。在最顶层,我们有两个路由, path="*" 和 path="/welcome" 。这两个路由是分开的,因为 

 和  在  页面上不可见。

在第二级,我们有两个路由, path="/catalog/" 和 index 。它们分别用于呈现  或  。正如您在上面的代码片段中看到的, 

 和  包含在 path="" 的 element 属性中,而不是像我们在平面结构中所做的那样在  和  中声明。

最后,在最里面的一层,还有两条路线。第一个路径使用 path=":id" 公开 :id 参数。由于此路由是 path="/catalog/*" 的嵌套路由,因此该路径构建在其父路径上,在 /catalog/:id 中匹配。当不存在 :id 时,将使用 index 路由。

尝试演示,就看到每个组件仅在需要时渲染,从而使该解决方案比我们之前看到的解决方案更加优化。

嵌套路由并不是一个新概念。早在 2009 年,我们就在 C# 的 MVC 框架上使用某种形式的嵌套路由。然而,仍然有开发人员选择扁平结构的情况,而嵌套路由将是更好的解决方案。虽然嵌套路由今天可以帮助你,但预计嵌套路由在不久的将来会变得更加重要,像Island Architecture这样的概念和像Remix这样的框架会越来越受欢迎。