React Router v4 - Keep scrolling position when switching components
I have two <Route>
s created with react-router.
- /cards -> List of cards game
- /cards/1 -> Detail of card game #1
When the user clicks on the "Return to list", I want to scroll the user where he was on the list.
How can I do this?
Answers
To scroll the user back to their previous position in the list of cards when they navigate back from a card detail page (/cards/1
) to the list page (/cards
), you can use the scrollTo
method provided by the browser's window
object in combination with React Router's useLocation
and useRef
hooks.
Here’s a step-by-step approach to achieve this:
Step-by-Step Implementation
1. Setup Scroll Restoration
React Router v5 and later provide a useLocation
hook that allows you to get the current location object. You can use this along with useRef
to store and restore the scroll position.
// ListCards.js
import React, { useEffect, useRef } from 'react';
import { Link, useLocation } from 'react-router-dom';
const ListCards = () => {
const location = useLocation();
const scrollRef = useRef(null);
useEffect(() => {
if (scrollRef.current) {
window.scrollTo(0, scrollRef.current.offsetTop);
}
}, [location.key]);
return (
<div>
{/* List of cards */}
<ul>
<li>
<Link to="/cards/1">Card #1</Link>
</li>
<li>
<Link to="/cards/2">Card #2</Link>
</li>
{/* Add more cards as needed */}
</ul>
{/* Store current scroll position */}
<div ref={scrollRef} />
{/* Additional content */}
</div>
);
};
export default ListCards;
2. Explanation
-
useLocation Hook: This hook from React Router provides access to the current location object. We use it to detect when the user navigates between different routes.
-
useRef Hook: This hook creates a mutable ref object (
scrollRef
) which can store a reference to a DOM element. In this case, it's used to create a placeholder div (<div ref={scrollRef} />
) where we store the scroll position. -
useEffect Hook: This hook runs after every render and is used to scroll the window to the position stored in
scrollRef.current.offsetTop
. This ensures that when the user navigates back to the list (/cards
), they are scrolled to the previous position in the list. -
Links to Detail Pages: These are represented by
<Link>
components that navigate to specific card detail pages (/cards/1
,/cards/2
, etc.).
3. Implementing Card Detail Page
On the card detail page (/cards/1
, /cards/2
, etc.), ensure you also have a link back to the list of cards. When the user clicks "Return to list", it should preserve the scroll position automatically.
// CardDetail.js
import React from 'react';
import { Link } from 'react-router-dom';
const CardDetail = ({ match }) => {
const { id } = match.params;
return (
<div>
<h2>Card Detail #{id}</h2>
{/* Detail content */}
<Link to="/cards">Return to list</Link>
</div>
);
};
export default CardDetail;
Summary
By using useLocation
to detect route changes and useRef
to store and restore scroll positions, you can effectively implement scroll restoration in your React application when navigating between list and detail pages. This approach ensures a smooth user experience where users are returned to their previous position in the list after viewing details of a card. Adjust the components and routes as needed based on your specific application structure and requirements.