Scrolling to top on page changes in React Router (v5)
Published on in JavaScript and React
A common solution is to scroll to top every time the page changes. That's incorrect: the page should be scrolled to top only when navigating to new pages, not when navigating back or forward.
Table of contents
Common but wrong solution
When navigating in a Single Page Application (SPA), you have to handle scrolling manually. Here's a solution that's often recommended, but this is wrong:
import { useLocation } from 'react-router-dom'
// Use this hook in some top-level component
// which is inside a `<Router>` component
function useOnPageChange() {
const { pathname } = useLocation()
useEffect(() => {
window.scrollTo(0, 0)
}, [pathname])
}
It's wrong because the page is scrolled to top on all page changes – even when using the browser's back and forward navigation buttons.
Compare with any non-SPA site, like my website or Wikipedia. When using the browser's back/forward buttons, the previous/next page's scrolling position should be restored. The page should be scrolled to top only when navigating to new pages.
Correct solution
The fix is to check the value of the
history
object's action
parameter:
import { useHistory, useLocation } from 'react-router-dom'
function useOnPageChange() {
const { action } = useHistory()
const { pathname } = useLocation()
useEffect(() => {
// Do nothing when using the browser's back/forward buttons
if (action === 'POP') return
window.scrollTo(0, 0)
}, [action, pathname])
}
You could (and probably should) also do other things in the hook, like focus the main heading of the new page.