admin管理员组

文章数量:1331884

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 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;
Share edited Nov 14, 2022 at 15:21 giosan asked Mar 29, 2022 at 16:23 giosangiosan 4071 gold badge8 silver badges19 bronze badges 2
  • If you are using a single page React app, I wouldn't expect onbeforeunload to fire on page navigation, since you're not actually leaving the page. Something like this might be useful: Detect Route Change with react-router – DBS Commented Mar 29, 2022 at 16:25
  • you can create a link and inside create a button and put the href=# – Elio Bteich Commented Mar 29, 2022 at 16:26
Add a ment  | 

2 Answers 2

Reset to default 4

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 (
    ...
  );
}

Here is my solution using React hooks:

const [showsScrolBtn, setShowScrolBtn] = useState(false);

useEffect(() => {
  const handleButtonVisibility = () => {
    window.pageYOffset > 300 ? setShowScrolBtn(true) : setShowScrolBtn(false);
  };

  window.addEventListener("scroll", handleButtonVisibility);
  return () => {
    window.addEventListener("scroll", handleButtonVisibility);
  };
}, []);

{
  showsScrolBtn && (
    <div
      id="scrolToTop"
      onClick={() => {
        window.scrollTo({
          top: 0,
          left: 0,
          behavior: "smooth",
        });
      }}
      style={{
        position: "fixed",
        bottom: "60px",
        right: "60px",
        color: "gray",
        textAlign: "center",
        cursor: "pointer",
        fontSize: "4em",
        lineHeight: 0,
        textDecoration: "none",
      }}
    >
      Click To Move Top
    </div>
  );
}

本文标签: javascriptScroll to top on browser back button click reactStack Overflow