React中如何监听返回按钮点击 仅从商品页返回分类页时恢复滚动位置
React监听返回按钮+滚动恢复修复方案
原有代码优化点
先修正现有滚动监听逻辑的性能问题:原代码将scrollPosition加入useEffect依赖,每次滚动都会重新绑定滚动事件,存在不必要的性能消耗,优化后代码如下:
const [scrollPosition, setScrollPosition] = React.useState(0); React.useEffect(() => { const pathName = document.location.pathname.substr(1); const handleScroll = () => { const currentScrollY = window.scrollY; setScrollPosition(currentScrollY); if(currentScrollY !== 0){ sessionStorage.setItem("scrollPosition_"+pathName, currentScrollY); } }; window.addEventListener('scroll', handleScroll); // 组件卸载时移除监听,避免内存泄漏 return () => window.removeEventListener('scroll', handleScroll); }, []);
核心需求实现方案
方案1:通过React Router判断上一个路由(推荐,准确率最高)
第一步:全局存储上一路由路径
在项目根组件App.js中全局维护前后路由的状态,方便所有页面调用:
import { useLocation } from 'react-router-dom'; import { useEffect } from 'react'; let prevPath = ''; let currentPath = ''; function App() { const location = useLocation(); useEffect(() => { prevPath = currentPath; currentPath = location.pathname; }, [location]); // 原有App组件其他逻辑 } export { prevPath };
第二步:分类页新增上一路由判断逻辑
修改分类页的滚动恢复逻辑,仅当从上一级是商品页时才触发滚动恢复,恢复完成后清空存储的滚动值,避免其他场景复用:
import { prevPath } from './App'; React.useEffect(() => { const pathName = document.location.pathname.substr(1); const savedScroll = sessionStorage.getItem("scrollPosition_"+pathName); // 替换为你项目实际的商品页路由正则规则,示例为匹配/goods/数字 格式的商品页路径 const isFromGoodsPage = /^\/goods\/\d+$/.test(prevPath); if (savedScroll && isFromGoodsPage) { // 原生方法实现滚动,无需依赖jQuery window.scrollTo(0, Number(savedScroll)); // 恢复完成后删除存储值,避免其他场景触发 sessionStorage.removeItem("scrollPosition_"+pathName); } }, []);
方案2:直接监听返回按钮触发的popstate事件
如果不需要严格限制来源页,仅需要点击返回按钮时才触发滚动恢复,可以直接监听popstate事件,该事件仅在用户点击浏览器前进/后退按钮、调用history.back()等历史操作时触发,普通路由跳转不会触发:
React.useEffect(() => { const pathName = document.location.pathname.substr(1); const handleBack = () => { const savedScroll = sessionStorage.getItem("scrollPosition_"+pathName); if (savedScroll) { window.scrollTo(0, Number(savedScroll)); sessionStorage.removeItem("scrollPosition_"+pathName); } }; window.addEventListener('popstate', handleBack); return () => window.removeEventListener('popstate', handleBack); }, []);
注意:如果项目中有其他调用返回方法的业务场景,该方案会同时触发,建议结合上一路由判断使用更稳妥。
内容的提问来源于stack exchange,提问作者user16468845
相关产品推荐
相关产品推荐

