I have 2 routes in my app, /validations
(which is a list) and /validations/:id
(which is the same list focused on a particular item).
I initially wrote my routes statically and everything works (as expected):
<Route path="/validations/:id" component={Validations} />
<Route path="/validations" component={Validations} />
However, because I wanted to do some refactoring, I put the routes in an array and used a .map
to render them. But with this, when I click on an item, the whole page rerender and I lose the scroll of the list (this is a bad UX for the user because he loses where he was in the list):
const routes = [
{
path: '/validations/:id',
component: Validations,
},
{
path: '/validations',
component: Validations,
},
]
// ...and in the JSX...
{routes.map(({ path, component }) => (
<Route
key={path}
path={path}
component={component}
/>
))}
Even stranger, if I remove the key
prop of the Route
I get back the initial behaviour (but I have a warning by React).
Did I write something wrong? Is it a react-router bug? A React one?
How can I keep the scroll of the list with my route mapping?
Here is a reproduction: https://codesandbox.io/s/vm71x2k46l
I knew something was fishy because I've done this many times and I didn't get your results. So I noticed that you render your sidebar inside your route.
This is why it's re-rendering and setting everything to the top. Because you actually navigate to another route.
What you must do is set your Sidebar links outside the actual routes but inside the Router Component.
Like in this sandbox: https://codesandbox.io/s/p2r4pl2o3q
If you notice I changed the routes a bit:
const routes = [
{
path: "/",
component: Index
},
{
exact: true,
path: "/validations",
component: Validations
},
{
path: "/validations/:id",
component: Validations
}
];
And then created the sidebar component and set it outside the routes
<BrowserRouter>
<div>
<Sidebar />
<div style={{ marginLeft: 150 }}>{routeComponents}</div>
</div>
</BrowserRouter>
Sidebar:
var items = Array.apply(null, Array(300)).map(function(x, i) {
return i;
});
export default () => (
<div
style={{
width: 150,
height: "100vh",
display: "flex",
overflow: "auto",
position: "absolute",
flexDirection: "column"
}}
>
{items.map((item, index) => (
<Link to={`/validations/${index}`} key={index}>
Item {index}
</Link>
))}
</div>
);
Now since first click the scroll doesn't reset.
PS: Please don't mind the styling decisions I was just trying to see something work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With