You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由切换时页面无法滚动到顶部问题求助

React路由切换时页面无法滚动到顶部问题

我正在开发一个React项目,需要在切换路由时让页面滚动到顶部。已经实现了ScrollToTop组件,但组件无效,页面导航后仍保留原滚动位置。

尽管已验证ScrollToTop组件的console.log可输出正确路径名,且组件已在App.js中正确引入并包裹Routes,但路由切换时页面仍未滚动到顶部。

排查步骤

  • 确认ScrollToTop.js中的console.log可正常输出正确路径名
  • 确保ScrollToTop组件已在App.js中引入并包裹Routes

补充信息

我实现的ScrollToTop组件使用useEffect钩子,预期在pathname变化时将页面滚动到顶部,但实际导航后页面仍保留原滚动位置,不符合预期。

我已查阅Stack Overflow所有相关帖子,尝试所有可用方案均无效,其他问题的解决方案不适用于我的场景。

App.js

import React, { useState, useRef } from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import NavBar from "./components/NavBar.js";
import Contact from "./components/Contact.js";
import Widgets from "./components/widgets/Widgets.js";
import Footer from "./components/Footer.js";
import Currency from "./components/widgets/Currency.js";
import Timer from "./components/widgets/Timer.js";
import Weather from "./components/widgets/Weather.js";
import MainPage from "./components/MainPage.js";
import ScrollToTop from "./components/ScrollToTop.js";

function App() {
  const [isSidebarVisible, setIsSidebarVisible] = useState(true);

  const toggleSidebar = () => setIsSidebarVisible(!isSidebarVisible);

  const personalRef = useRef(null);
  const skillsRef = useRef(null);
  const workRef = useRef(null);
  const educationRef = useRef(null);
  const publicationsRef = useRef(null);

  const refs = {
    personal: personalRef,
    skills: skillsRef,
    work: workRef,
    education: educationRef,
    publications: publicationsRef,
  };

  return (
    <Router>
      <ScrollToTop />
      <div className="flex min-h-screen overflow-hidden">
        <NavBar 
          isSidebarVisible={isSidebarVisible} 
          toggleSidebar={toggleSidebar} 
          refs={refs}
        />
        <div
          className={`flex-1 flex flex-col transition-all duration-300 ${
            isSidebarVisible ? "ml-20" : "ml-0"
          }`}
        >
          <header className="flex justify-between items-center p-8 bg-gray-800 text-white fixed w-full top-0 left-0 z-30 transition-all duration-300">
            <h1
              className={`text-2xl transition-all duration-300 ${
                isSidebarVisible ? "ml-20" : "ml-0"
              }`}
            >
              Richard Lechko - IT Student @ DePaul University
            </h1>
            <button
              onClick={toggleSidebar}
              className="p-2 bg-blue-500 text-white rounded"
            >
              {isSidebarVisible ? "Close Sidebar" : "Open Sidebar"}
            </button>
          </header>
          <main className="flex-1 flex flex-col pt-24 overflow-hidden">
            <Routes>
              <Route
                path="/"
                element={
                  <MainPage
                    personalRef={personalRef}
                    skillsRef={skillsRef}
                    workRef={workRef}
                    educationRef={educationRef}
                    publicationsRef={publicationsRef}
                  />
                }
              />
              <Route path="/contact" element={<Contact />} />
              <Route path="/widgets" element={<Widgets />} />
              <Route path="/widgets/currency" element={<Currency />} />
              <Route path="/widgets/timer" element={<Timer />} />
              <Route path="/widgets/weather" element={<Weather />} />
            </Routes>
            <Footer refs={refs} />
          </main>
        </div>
      </div>
    </Router>
  );
}

export default App;

ScrollToTop.js

import { useEffect } from "react";
import { useLocation } from "react-router-dom";

const ScrollToTop = () => {
  const { pathname } = useLocation();

  useEffect(() => {
    console.log('ScrollToTop: Pathname changed to', pathname);
    setTimeout(() => {
      window.scrollTo(0, 0);
    }, 0);
  }, [pathname]);

  return null;
};

export default ScrollToTop;
import React, { useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import {
  FaUser,
  FaTools,
  FaBriefcase,
  FaGraduationCap,
  FaBook,
  FaEnvelope,
} from "react-icons/fa";

const NavBar = ({ isSidebarVisible, refs, toggleSidebar }) => {
  const navigate = useNavigate();
  const location = useLocation();

  const handleNavClick = (sectionId) => {
    if (refs[sectionId] && refs[sectionId].current) {
      refs[sectionId].current.scrollIntoView({ behavior: "smooth" });
    } else {
      navigate("/");
      setTimeout(() => {
        if (refs[sectionId] && refs[sectionId].current) {
          refs[sectionId].current.scrollIntoView({ behavior: "smooth" });
        }
      }, 100);
    }
  };

  const handleExternalNavClick = (path) => {
    navigate(path, { replace: true });
  };

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [location.pathname]);

  return (
    <div
      className={`fixed top-0 h-screen ${
        isSidebarVisible ? "w-20" : "w-0"
      } bg-gray-900 text-white shadow-lg transition-all duration-300 z-40`}
    >
      <nav>
        <ul>
          <NavItem icon={<FaUser size={28} />} onClick={() => handleNavClick('personal')} />
          <NavItem icon={<FaTools size={28} />} onClick={() => handleNavClick('skills')} />
          <NavItem icon={<FaBriefcase size={28} />} onClick={() => handleNavClick('work')} />
          <NavItem icon={<FaGraduationCap size={28} />} onClick={() => handleNavClick('education')} />
          <NavItem icon={<FaBook size={28} />} onClick={() => handleNavClick('publications')} />
          <NavItem icon={<FaEnvelope size={28} />} onClick={() => handleExternalNavClick('/contact')} />
          <NavItem icon={<FaTools size={28} />} onClick={() => handleExternalNavClick('/widgets')} />
        </ul>
      </nav>
    </div>
  );
};

const NavItem = ({ icon, onClick }) => {
  return (
    <li onClick={onClick}>
      <div className="flex justify-center items-center p-4 hover:bg-gray-700 transition-colors cursor-pointer">
        {icon}
      </div>
    </li>
  );
};

export default NavBar;

内容的提问来源于stack exchange,提问作者Richard Lechko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:52:03