繁体   English   中英

React Router如何递归创建页面?

[英]How does React Router recursively create pages?

我在这里谈论这个例子: https//reacttraining.com/react-router/web/example/recursive-paths

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

const PEEPS = [
  { id: 0, name: "Michelle", friends: [1, 2, 3] },
  { id: 1, name: "Sean", friends: [0, 3] },
  { id: 2, name: "Kim", friends: [0, 1, 3] },
  { id: 3, name: "David", friends: [1, 2] }
];

function find(id) {
  return PEEPS.find(p => p.id == id);
}

function RecursiveExample() {
  return (
    <Router>
      <Person match={{ params: { id: 0 }, url: "" }} />
    </Router>
  );
}

function Person({ match }) {
  let person = find(match.params.id);

  return (
    <div>
      <h3>
        {person.name}
        ’s Friends
      </h3>
      <ul>
        {person.friends.map(id => (
          <li key={id}>
            <Link to={`${match.url}/${id}`}>{find(id).name}</Link>
          </li>
        ))}
      </ul>
      <Route path={`${match.url}/:id`} component={Person} />
    </div>
  );
}

export default RecursiveExample;

在这个例子中,我理解递归如何一次一步地工作。 令我困惑的是,当(在那个迷你浏览器中)如果我在刷新页面之后直接放入此链接, /1/0/3/2/3/2 1/0/3/2/3/2或任何其他嵌套示例时,React Router如何知道以正确的顺序呈现组件。 没有明确的路径路径匹配+ /:id1/:id2/:id3等。

我知道这是不可行的,因为它可以直到无限,但React Router如何能够解决这个问题呢?

TLDR; 这里的主要技巧是,只要呈现的Routepath与URL匹配,持有RoutePerson组件每次都会呈现自身。


细节

按照设计,只有当Route的path prop与页面的URL匹配时,才会传递传递给Route的component prop的component

{/* Something will get rendered when the URL /whatever matches the URL of the page */}
<Route path="/whatever" component={Something}>

由于我们只在点击时渲染一个嵌套的Person (有自己的Route ),我们可以无限期地继续生成这些递归路由。

每次渲染一个Person ,它都会在其中呈现一个Route作为下一个Person的占位符。

function Person({ match }) {
  // ...

  return (
    <div>
      {/* ... */}
      {/* this route is a placeholder for the next Person */}
      <Route path={`${match.url}/:id`} component={Person} />
    </div>
  );
}

如果其拥有的Routepath与URL匹配,则会呈现此下一个Person 拥有Routepath是父级的URL加上另一个id,即match.url + '/:id'

这就是我们如何获得递归渲染。 Person呈现一个Route这使得一个Person这使得一个Route ......这重复进行,直到最后呈现的Routepath不匹配的页面URL。

注意: match propRoute传递到作为component prop传递到该Routecomponent 这就是Person可以访问它的方式。

有一点需要注意:应用程序总是从Michelle的朋友(即id0的人的朋友)开始,因为:

function RecursiveExample() {
  return (
    <Router>
      {/* This part of the code passes in a fake `match` prop to always start of the app from Michelle's point of view */}
      <Person match={{ params: { id: 0 }, url: "" }} />
    </Router>
  );
}

这意味着,不管如果首先在打开网页或刷新页面/0/1/2阵营路由器总是呈现Michelle作为第一Person这将呈现一个嵌套<Route path='/:id' component={Person} />

这意味着应用程序的初始状态始终如下:

<RecursiveExample>
  <BrowserRouter>
    <Person>
      <Route path="/:id" />
    </Person>
  </BrowserRouter>
</RecursiveExample>

其呈现为:

应用程序总是从米歇尔的朋友开始

如果应用程序已加载到/ ,则渲染将停止在上述状态,直到我们开始与应用程序进行交互。

但是,如果我们在/0/1/2 0/1/2刷新页面,渲染将继续。 上面所示的初始状态被呈现之后,阵营路由器将找出path ,从<Route path="/:id" />匹配/0/1/2的URL(通过取0忽略其余部分),填补id0并渲染下一个Personid0那个)。

注意:上面的URL匹配是有效的,因为Route的默认匹配策略是忽略路径末尾的任何多余字符。 这就是为什么/:id匹配/0/1/2id0并忽略/1/2部分。 我们可以使用exact prop来强制匹配,确切地说,但是这会破坏递归行为,即/:id只匹配/0而不是/0/1/2

此时我们的树看起来像:

<RecursiveExample>
  <BrowserRouter>
    <Person>
      <Route path="/:id" {/* this matches /0 */}
        <Person>
          {/* we're here during the rendering stage */}
        </Person>
      </Route>
    <Person>
  </BrowserRouter>
</RecursiveExample>

在这个阶段呈现的人恰好是Michelle (因为id 0 )。

第二阶段还展示了米歇尔的朋友

Person现在重复该过程。 它呈现自己的嵌套Route ,现在path/0/:id (因为它将/:id连接到父url), component再次作为Person 由于/0/:id仍然匹配/0/1/2 (id现在为1 ),我们渲染下一个Person

此时树是:

<RecursiveExample>
  <BrowserRouter>
    <Person>
      <Route path="/:id" {/* this matches /0 */}
        <Person>
          <Route path="/0/:id"> {/* this matches /0/1 */}
            <Person>
              {/* we're here during the rendering stage */}
            </Person>
          </Route>
        </Person>
      </Route>
    <Person>
  </BrowserRouter>
</RecursiveExample>

树现在显示id等于1的人的朋友:

现在我们向肖恩的朋友们展示

你能看出这是怎么回事吗?

重复此过程,直到在最后一个呈现的Person中呈现的Routepath与URL不匹配。 在刷新/0/1/2 URL的情况下,这将是具有path /0/1/2/:idRoute

这是最终的React树的外观:

<RecursiveExample>
  <BrowserRouter>
    <Person>
      <Route path="/:id" {/* this matches /0 */}
        <Person>
          <Route path="/0/:id"> {/* this matches /0/1 */}
            <Person>
              <Route path="/0/1/:id"> {/* this matches /0/1/2 */}
                <Person>
                  <Route path="/0/1/2/:id" /> {/* this isn't matched yet */}             
                </Person>
              </Route>
            </Person>
          </Route>
        </Person>
      </Route>
    <Person>
  </BrowserRouter>
</RecursiveExample>

这是最终的申请状态:

最终呈现状态


现在,无论我们实际刷新页面在/0/1/2还是单击链接到达它,行为都是一样的。

重要的是要记住,它是控制渲染内容的URL。

通过刷新或通过手动键入特定URL启动应用程序时,只要每个呈现的路径的路径与URL匹配,React Router就会自动(上面显示的前几个)遍历嵌套的Person呈现阶段。

另一方面,每次我们点击指向特定URL的链接时,我们都会手动触发URL更改,从而触发下一个Person的呈现阶段。

我们是手动键入URL还是通过单击创建URL,如果生成的URL相同,则呈现的应用程序也是相同的。 不同之处在于我们如何进入最终渲染状态。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM