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;
NavBar.js
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
相关产品推荐
相关产品推荐

