我在这里谈论这个例子: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
或任何其他嵌套示例后直接放置此链接,React Router如何知道以正确的方式呈现组件订购。没有匹配+ /:id1/:id2/:id3
等的明确路由路径。
我知道这是不可行的,因为它可以达到无穷远,但是React Router如何解决这个问题?
答案 0 :(得分:1)
TLDR; 这里的主要技巧是,只要渲染的{{的Person
1}}与网址匹配。
详细信息
根据设计,仅当Route的Route
道具与页面的URL匹配时,才会呈现传递给Route的path
道具的组件。
Route
由于我们仅在点击时渲染嵌套的component
(具有自己的path
),因此我们可以无限期地生成这些递归路由。
每次渲染{/* Something will get rendered when the URL /whatever matches the URL of the page */}
<Route path="/whatever" component={Something}>
时,它都会在其中渲染Person
作为下一个Route
的占位符。
Person
如果下一个Route
的{{1}}与URL相匹配,则呈现下一个Person
。拥有的function Person({ match }) {
// ...
return (
<div>
{/* ... */}
{/* this route is a placeholder for the next Person */}
<Route path={`${match.url}/:id`} component={Person} />
</div>
);
}
的{{1}}是父级的URL加上另一个ID,即Person
。
这就是我们获得递归渲染的方式。 Route
渲染path
,渲染Route
,渲染path
...重复直到最后渲染的match.url + '/:id'
的{{1}}页面网址不匹配。
注意:match
prop由Person
传递到作为Route
属性传递到该Person
中的组件。 Route
就是这种访问方式。
需要注意的一件事:由于以下原因,应用程序总是以Route
的朋友(即path
为Route
的人的朋友)开头,
component
这意味着无论您是第一次打开页面还是在Route
刷新页面,React Router始终将Person
渲染为第一个Michelle
,这将渲染嵌套的{{1 }}。
这意味着应用程序的初始状态始终如下所示:
id
哪个呈现为:
如果应用程序是在0
加载的,则渲染将停止在上述状态,直到我们开始与该应用程序进行交互为止。
但是,如果我们刷新页面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>
);
}
,则呈现将继续。呈现以上所示的初始状态后,React Router将发现/0/1/2
中的Michelle
与Person
URL匹配(通过使<Route path='/:id' component={Person} />
忽略其余部分),填充<RecursiveExample>
<BrowserRouter>
<Person>
<Route path="/:id" />
</Person>
</BrowserRouter>
</RecursiveExample>
作为/
,并渲染下一个/0/1/2
(将path
作为<Route path="/:id" />
的那个)。
注意:上面的URL匹配之所以有效,是因为/0/1/2
的默认匹配策略是忽略路径末尾的任何多余字符。这就是0
与id
匹配,0
为Person
且id
部分被忽略的原因。我们可以使用exact
prop强制匹配完全正确,但这会破坏递归行为,即0
仅匹配Route
而不匹配/:id
这时我们的树看起来像:
/0/1/2
在此阶段渲染的人恰好又是id
(由于0
/1/2
)。
此/: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
连接到父URL),又id
再次为{{1 }}。由于0
仍与Person
匹配(ID现在为Route
),因此我们呈现下一个path
。
这时树是:
/0/:id
树现在显示/:id
等于component
的人的朋友:
您能看到前进的方向吗?
重复此过程,直到最后渲染的Person
中渲染的/0/:id
的{{1}}与URL不匹配为止。在/0/1/2
URL刷新的情况下,将是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>
。
这是最终的React树的样子:
id
这是最终的应用程序状态:
现在,无论我们实际上是刷新1
上的页面还是单击链接进行访问,其行为都是相同的。
重要的是要记住,它是控制呈现内容的URL。
通过刷新或手动键入特定URL来启动应用程序时,React Router会自动完成嵌套的path
渲染阶段(上面显示的前几个),只要每个渲染路径的路径都可以匹配网址。
另一方面,每次我们单击指向特定URL的链接时,我们都会手动触发URL更改,从而触发下一个Route
的呈现阶段。
我们是手动键入URL还是通过单击创建URL,如果结果URL相同,则呈现的应用程序也相同。 区别在于我们如何达到最终的渲染状态。