如何使用嵌套路由向页面添加内容而不用 react-router-v4 删除先前路由的内容?
How to use nested routes to add content to a page without removing the content of the previous route with react-router-v4?
我正在使用 react-router-v4 官方文档中提供的边栏示例作为灵感 https://reacttraining.com/react-router/web/example/sidebar
1- 所以我的申请的初始 URL 将是:localhost:3000/search-page/Lists
2- 我有一个可点击的 Link 列表,点击后会在边栏上显示点击的数据,发生这种情况时 URL 会更新:localhost:3000/search-page/Lists/itemList1selected
3- 然后我按下按钮 "Show List number 2" 以显示新列表
4- 我的目标是使用嵌套路由,当我点击 "List number 2" 中的 Link 时。它会将其附加到从 "List number 1" 中选择的项目下方...并同时更新 URL :localhost:3000/search-page/Lists/itemList1selected/itemList2selected
这是我当前的代码:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
showListButtonPressed: true
};
this.showTheOtherList = this.ShowTheOtherList.bind(this);
}
showTheOtherList() {
this.setState({
showListButtonPressed: !this.state.showListButtonPressed
});
}
render() {
const dataList1 = dataFromDataBase
.allItemsFromList1()
.map(list1 => ({
path: `${this.props.match.params.type}/${list1.id}`,
mainList1: () => (
<div>
{`${list1.company} ${list1.name} ${list1.price}`}
</div>
),
sidebarList1: () => (
<div>
<h3>item List 1 selected</h3>
{list1.company}
</div>
)
}));
const dataList2 = fakeFlightApiDataTesting
.allItemsFromList2()
.map(list2 => ({
path: `${this.props.match.params.type}/${list2.id}`,
mainList2: () => (
<div>
{`${list2.company} ${list2.name} ${list2.price}`}
</div>
),
sidebarList2: () => (
<div>
<h3>item List 2 selected</h3>
{list2.company}
</div>
)
}));
return (
<div style={{ display: 'flex' }}>
<div style={{ width: '20%' }}>
{dataList1.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
component={route.sidebarList1}
/>
</div>
))}
{dataList2.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
component={route.sidebarList2}
/>
</div>
))}
</div>
<div>
// Switch the lists when button is pressed
{this.state.showListButtonPressed ? (
<div>
<ul>
{dataList1.map(route => (
<li key={route.path}>
<Link to={`/search-page/${route.path}`}>
{route.mainList1()}
</Link>
</li>
))}
</ul>
<button onClick={this.showTheOtherList}>
Switch Lists
</button>
</div>
) : (
<div>
<ul>
{dataList2.map(route => (
<li key={route.path}>
<Link to={`/search-page/${route.path}`}>
{route.mainList2()}
</Link>
</li>
))}
</ul>
<button onClick={this.showTheOtherList}>
switch Lists
</button>
</div>
)}
</div>
</div>
);
}
}
这里有一些截图可以让你有更好的想法:
您可以使用不同的方法来解决这个问题:
- 从官方 React Router v4 中获得另一个灵感 recursive paths。
使用此模式,您可以创建深度嵌套的列表,深度超过 2 层。
- 检查是否已经在侧边栏的第一级选择了 1 个项目,并为这种情况呈现另一个
<SidebarRoute />
,将第二级选择的项目作为道具传递。
我建议您(第 3 个选项)将所选项目保持在状态中,并相应地在边栏中呈现。如果您没有义务通过电子邮件或其他方式发送链接,那么此选项会很好用,只是想呈现。然后你可以将 UI state 保存在你选择的存储中(redux,flux,你的名字)。
第二种方法的基本示例(idlvl2 是您要在边栏中显示的内容):https://codesandbox.io/s/o53pq1wvz
这可能只是一个错字,但在您的渲染组件中,您忘记了将 Router 添加到最外层 div。路由组件必须在路由器组件内定义。
在我看来,您可以使用搜索参数。
但是,如果您没有机会更改路径接收器组件的逻辑,则需要 recursive paths 建议的路由。
关于搜索参数。因此,不要添加 localhost:3000/search-page/Lists/itemList1selected/itemList2selected
,而是添加 localhost:3000/search-page/Lists?item1=itemList1selected&item2=itemList2selected
。
您可以通过 URLSearchParams 提取值,请注意 IE 不支持它。
这种方法有 3 个优点。首先,它将始终呈现 List,它将处理逻辑,不需要嵌套的路由。其次,您可以添加多个项目,而不仅仅是两个。第三个 url 将处理所有逻辑,您可以共享 link 并期待相同的结果。
困难的部分是,由于您使用的是 2 个路径参数,因此它的功能与他们使用的示例并不完全相同。假设您有 "n" list1 选项和 "m" list2 选项。这意味着您将有 n x m 条总路线。要让它像这样工作,您需要创建一个与每个 list1 选项结合的 list2 路由。那么 list2 的 path
键看起来像 ${this.props.match.params.type}/${list1.id}/${list2.id}
。我认为这也可以通过为 list2 ${this.props.match.url}/${list2.id}
设置路径来实现,但这需要始终首先选择 list1。
这是一个非常棘手的案例,但我希望对您有所帮助
我正在使用 react-router-v4 官方文档中提供的边栏示例作为灵感 https://reacttraining.com/react-router/web/example/sidebar
1- 所以我的申请的初始 URL 将是:localhost:3000/search-page/Lists
2- 我有一个可点击的 Link 列表,点击后会在边栏上显示点击的数据,发生这种情况时 URL 会更新:localhost:3000/search-page/Lists/itemList1selected
3- 然后我按下按钮 "Show List number 2" 以显示新列表
4- 我的目标是使用嵌套路由,当我点击 "List number 2" 中的 Link 时。它会将其附加到从 "List number 1" 中选择的项目下方...并同时更新 URL :localhost:3000/search-page/Lists/itemList1selected/itemList2selected
这是我当前的代码:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
showListButtonPressed: true
};
this.showTheOtherList = this.ShowTheOtherList.bind(this);
}
showTheOtherList() {
this.setState({
showListButtonPressed: !this.state.showListButtonPressed
});
}
render() {
const dataList1 = dataFromDataBase
.allItemsFromList1()
.map(list1 => ({
path: `${this.props.match.params.type}/${list1.id}`,
mainList1: () => (
<div>
{`${list1.company} ${list1.name} ${list1.price}`}
</div>
),
sidebarList1: () => (
<div>
<h3>item List 1 selected</h3>
{list1.company}
</div>
)
}));
const dataList2 = fakeFlightApiDataTesting
.allItemsFromList2()
.map(list2 => ({
path: `${this.props.match.params.type}/${list2.id}`,
mainList2: () => (
<div>
{`${list2.company} ${list2.name} ${list2.price}`}
</div>
),
sidebarList2: () => (
<div>
<h3>item List 2 selected</h3>
{list2.company}
</div>
)
}));
return (
<div style={{ display: 'flex' }}>
<div style={{ width: '20%' }}>
{dataList1.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
component={route.sidebarList1}
/>
</div>
))}
{dataList2.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
component={route.sidebarList2}
/>
</div>
))}
</div>
<div>
// Switch the lists when button is pressed
{this.state.showListButtonPressed ? (
<div>
<ul>
{dataList1.map(route => (
<li key={route.path}>
<Link to={`/search-page/${route.path}`}>
{route.mainList1()}
</Link>
</li>
))}
</ul>
<button onClick={this.showTheOtherList}>
Switch Lists
</button>
</div>
) : (
<div>
<ul>
{dataList2.map(route => (
<li key={route.path}>
<Link to={`/search-page/${route.path}`}>
{route.mainList2()}
</Link>
</li>
))}
</ul>
<button onClick={this.showTheOtherList}>
switch Lists
</button>
</div>
)}
</div>
</div>
);
}
}
这里有一些截图可以让你有更好的想法:
您可以使用不同的方法来解决这个问题:
- 从官方 React Router v4 中获得另一个灵感 recursive paths。
使用此模式,您可以创建深度嵌套的列表,深度超过 2 层。
- 检查是否已经在侧边栏的第一级选择了 1 个项目,并为这种情况呈现另一个
<SidebarRoute />
,将第二级选择的项目作为道具传递。
我建议您(第 3 个选项)将所选项目保持在状态中,并相应地在边栏中呈现。如果您没有义务通过电子邮件或其他方式发送链接,那么此选项会很好用,只是想呈现。然后你可以将 UI state 保存在你选择的存储中(redux,flux,你的名字)。
第二种方法的基本示例(idlvl2 是您要在边栏中显示的内容):https://codesandbox.io/s/o53pq1wvz
这可能只是一个错字,但在您的渲染组件中,您忘记了将 Router 添加到最外层 div。路由组件必须在路由器组件内定义。
在我看来,您可以使用搜索参数。
但是,如果您没有机会更改路径接收器组件的逻辑,则需要 recursive paths 建议的路由。
关于搜索参数。因此,不要添加 localhost:3000/search-page/Lists/itemList1selected/itemList2selected
,而是添加 localhost:3000/search-page/Lists?item1=itemList1selected&item2=itemList2selected
。
您可以通过 URLSearchParams 提取值,请注意 IE 不支持它。
这种方法有 3 个优点。首先,它将始终呈现 List,它将处理逻辑,不需要嵌套的路由。其次,您可以添加多个项目,而不仅仅是两个。第三个 url 将处理所有逻辑,您可以共享 link 并期待相同的结果。
困难的部分是,由于您使用的是 2 个路径参数,因此它的功能与他们使用的示例并不完全相同。假设您有 "n" list1 选项和 "m" list2 选项。这意味着您将有 n x m 条总路线。要让它像这样工作,您需要创建一个与每个 list1 选项结合的 list2 路由。那么 list2 的 path
键看起来像 ${this.props.match.params.type}/${list1.id}/${list2.id}
。我认为这也可以通过为 list2 ${this.props.match.url}/${list2.id}
设置路径来实现,但这需要始终首先选择 list1。
这是一个非常棘手的案例,但我希望对您有所帮助