useEffect+React Router搭配useLocation时滚轮路由切换未正常禁用
问题根源
问题出在闭包导致的滚动事件监听器逻辑未更新:
当你通过链接跳转到/work/portfolio时,组件虽然会因location变化重新渲染,但之前绑定到window上的滚动监听器,依然持有路由跳转前的handleNavigation函数——这个旧函数里捕获的location还是跳转前的路由值,所以判断逻辑不会生效,滚轮依然能触发路由切换。
哪怕你把location加入了useEffect的依赖数组,如果handleNavigation没有正确关联location的更新,旧的监听器要么没被正确移除,要么新的监听器逻辑没同步最新路由。
修复方案
方案1:在useEffect内部定义handleNavigation
把滚轮处理函数直接写在useEffect里,这样每次location变化时,都会生成一个绑定了最新location的新函数,同时移除旧的监听器:
import { useEffect, useLocation, useNavigate } from 'react-router-dom'; // 假设你有获取上/下路由的逻辑 const getPrevRoute = () => { /* ... */ }; const getNextRoute = () => { /* ... */ }; const ScrollRouteSwitcher = () => { const location = useLocation(); const navigate = useNavigate(); useEffect(() => { const handleNavigation = (e) => { // 实时判断当前路由,禁用目标路由的滚轮切换 if (location.pathname === '/work/portfolio') { return; } // 原有滚轮路由切换逻辑 const prevRoute = getPrevRoute(); const nextRoute = getNextRoute(); if (e.deltaY > 0) { navigate(nextRoute); } else { navigate(prevRoute); } }; window.addEventListener('wheel', handleNavigation); // 清理时移除对应的监听器 return () => window.removeEventListener('wheel', handleNavigation); }, [location, navigate]); // 依赖location确保路由变化时更新监听器 return null; };
方案2:用useCallback包裹handleNavigation
如果handleNavigation需要在组件其他地方复用,用useCallback绑定location作为依赖,确保函数始终持有最新路由信息:
import { useEffect, useCallback, useLocation, useNavigate } from 'react-router-dom'; const ScrollRouteSwitcher = () => { const location = useLocation(); const navigate = useNavigate(); const handleNavigation = useCallback((e) => { if (location.pathname === '/work/portfolio') { return; } const prevRoute = getPrevRoute(); const nextRoute = getNextRoute(); if (e.deltaY > 0) { navigate(nextRoute); } else { navigate(prevRoute); } }, [location, navigate]); // 依赖location保证函数更新 useEffect(() => { window.addEventListener('wheel', handleNavigation); return () => window.removeEventListener('wheel', handleNavigation); }, [handleNavigation]); // 依赖更新后的handleNavigation return null; };
核心注意事项
- 必须保证添加和移除的监听器是同一个函数引用:上面两种写法都能做到这一点,避免旧监听器残留。
- 路由判断要在事件触发时实时获取
location.pathname,而不是用初始化时的固定值,这样才能准确判断当前路由状态。
内容的提问来源于stack exchange,提问作者jacksonmendoza
相关产品推荐
相关产品推荐

