I'm using the sidebar example provided in the official documentation of react-router-v4 as an inspiration
1- So the initial URL of my application would be : localhost:3000/search-page/Lists
2- I have a list of clickable Links that when clicked display the clicked data on the sidebar, and when this happens the URL gets updated : localhost:3000/search-page/Lists/itemList1selected
3- I then press on the button "Show List number 2" to display a new list
4- my goal is using nested routes, when I click on a Link from "List number 2". it would append it below the item selected from "List number 1" ... and update the URL at the same time : localhost:3000/search-page/Lists/itemList1selected/itemList2selected
here's my current code :
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>
{`${list1pany} ${list1.name} ${list1.price}`}
</div>
),
sidebarList1: () => (
<div>
<h3>item List 1 selected</h3>
{list1pany}
</div>
)
}));
const dataList2 = fakeFlightApiDataTesting
.allItemsFromList2()
.map(list2 => ({
path: `${this.props.match.params.type}/${list2.id}`,
mainList2: () => (
<div>
{`${list2pany} ${list2.name} ${list2.price}`}
</div>
),
sidebarList2: () => (
<div>
<h3>item List 2 selected</h3>
{list2pany}
</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}
ponent={route.sidebarList1}
/>
</div>
))}
{dataList2.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
ponent={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>
);
}
}
here are some screenshots to have a better idea :
I'm using the sidebar example provided in the official documentation of react-router-v4 as an inspiration https://reacttraining./react-router/web/example/sidebar
1- So the initial URL of my application would be : localhost:3000/search-page/Lists
2- I have a list of clickable Links that when clicked display the clicked data on the sidebar, and when this happens the URL gets updated : localhost:3000/search-page/Lists/itemList1selected
3- I then press on the button "Show List number 2" to display a new list
4- my goal is using nested routes, when I click on a Link from "List number 2". it would append it below the item selected from "List number 1" ... and update the URL at the same time : localhost:3000/search-page/Lists/itemList1selected/itemList2selected
here's my current code :
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.pany} ${list1.name} ${list1.price}`}
</div>
),
sidebarList1: () => (
<div>
<h3>item List 1 selected</h3>
{list1.pany}
</div>
)
}));
const dataList2 = fakeFlightApiDataTesting
.allItemsFromList2()
.map(list2 => ({
path: `${this.props.match.params.type}/${list2.id}`,
mainList2: () => (
<div>
{`${list2.pany} ${list2.name} ${list2.price}`}
</div>
),
sidebarList2: () => (
<div>
<h3>item List 2 selected</h3>
{list2.pany}
</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}
ponent={route.sidebarList1}
/>
</div>
))}
{dataList2.map(route => (
<div>
<Route
key={route.path}
path={`/search-page/${route.path}`}
exact={route.exact}
ponent={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>
);
}
}
here are some screenshots to have a better idea :
Share Improve this question edited Dec 18, 2017 at 11:11 Vikas Yadav 3,3542 gold badges23 silver badges22 bronze badges asked Dec 15, 2017 at 0:46 AziCodeAziCode 2,7026 gold badges28 silver badges58 bronze badges
4 Answers
Reset to default 5 +50The difficult part is that since you're using 2 path params, it doesn't function exactly the same as the example they use. Let's say you have "n" list1 options, and "m" list2 options. That means you would n x m total routes. For it to work like this, you would need to create a list2 route bined with every list1 option. Then the path
key for list2 would look something like ${this.props.match.params.type}/${list1.id}/${list2.id}
. I think this could also be achieved this by making the path for list2 ${this.props.match.url}/${list2.id}
, but it would require that the list1 is always selected first.
It's a pretty tricky case, but I hope that helps
You can use different approaches to solve this:
- Get another inspiration from official React Router v4 recursive paths.
Using this pattern you can create deeply nested lists, more than 2 levels deep.
- Check if there are already 1 item selected at first level in your sidebar and render another
<SidebarRoute />
for that case, passing second level seleted item as a prop.
I would suggest you (3rd option) to hold selected items in state, and render accordingly in sidebar. This option will work out just fine, if you are not obligated to send links by e-mail or something, just want to render. Then you can save UI state in the store of your choice (redux, flux, you name it).
Basic example for 2nd approach (idlvl2 is what you are trying to show in sidebar): https://codesandbox.io/s/o53pq1wvz
This might just be a typo, but in your render ponent, you have forgotten to add Router to your outermost div. Route ponents have to be defined inside a Router ponent.
In my opinion, you can use search params.
However if you have no chance to change the logic of path receiver ponent, you need recursive paths Routes as suggested.
So about the search params. So instead of adding localhost:3000/search-page/Lists/itemList1selected/itemList2selected
, add localhost:3000/search-page/Lists?item1=itemList1selected&item2=itemList2selected
.
You can extract values by URLSearchParams, beware it does not supported by IE.
There are 3 pros to this approach. First it will always render List, which will handle the logic, no need of nested Routes. Second you can add several items, not just two. Third url will handle all the logic, you can share the link and expect the same result.