I need to scroll to the top every time the URL changes in my project (and on page reload).
Everything is working but I am having a problem with the browser back button. Even if the pathname changes the page doesn't scroll to the top as it should, it works on all other cases (page reload and regular link navigation).
I tried to counter that by creating a custom hook just for the back button, but it's not behaving how I want. I also tried a bunch of other things, but nothing seems to work as for the browser back button
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
const ScrollToTop = () => {
const { pathname } = useLocation();
const useBackButton = () => {
const [isBack, setIsBack] = useState(false);
const handleEvent = () => {
setIsBack(true);
};
useEffect(() => {
window.addEventListener("popstate", handleEvent);
return () => window.removeEventListener("popstate", handleEvent);
});
return isBack;
};
const backButton = useBackButton();
console.log(backButton);
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname, backButton]);
useEffect(() => {
window.onbeforeunload = () => {
window.scrollTo(0, 0);
};
}, []);
return null;
};
export default ScrollToTop;
I don't think the beforeunload
event is necessary here, but will include it anyway. Instead of using an event listener for the "popstate" event you can use the useNavigationType
hook to expressly check for a POP event type.
Note: Use window.addEventListener
for the beforeunload
event so you don't pollute/mutate the window
object.
Example:
import { NavigationType, useLocation, useNavigationType } from "react-router-dom";
const useBackButton = () => {
const navType = useNavigationType();
return navType === NavigationType.Pop;
};
const useScrollToTop = () => {
const { pathname } = useLocation();
const isPop = useBackButton();
const scrollToTop = () => window.scrollTo(0, 0);
useEffect(() => {
scrollToTop();
}, [pathname, isPop]);
useEffect(() => {
window.addEventListener("beforeunload", scrollToTop);
return () => {
window.removeEventListener("beforeunload", scrollToTop);
};
}, []);
};
Usage:
function App() {
useScrollToTop();
return (
...
);
}