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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:55:18