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

React Router中useEffect与useLocation同步异常:滚轮导航失效问题

问题诊断与解决方案

核心问题

你遇到的是闭包捕获旧值的问题:当从/work路由点击进入嵌套路由时,ContextProvider中绑定的handleNavigation函数仍然引用着路由切换前的location.pathname(也就是/work),所以location.pathname.includes('/work/')的判断不成立,滚轮导航依旧触发。而手动在地址栏输入嵌套路由时,组件会重新挂载,location是最新的嵌套路径,判断自然生效。


解决方案1:让事件处理函数依赖最新的location

用useCallback包裹handleNavigation,并将location加入依赖数组,确保路由变化时,函数能重新创建并捕获最新的路径值:

import { useNavigate, useLocation } from 'react-router-dom';
import { useEffect, useCallback } from 'react';

function ContextProvider({ children }) {
  const navigate = useNavigate();
  const location = useLocation();
  const routes = ['/main', '/skills', '/aboutme', '/work'];

  // 用useCallback包裹,确保路由变化时函数更新
  const handleNavigation = useCallback((e) => {
    // 用startsWith更精准,避免误判类似/mywork/的路径
    if (location.pathname.startsWith('/work/')) {
      return;
    }

    const currentIndex = routes.findIndex(route => route === location.pathname);
    let newIndex = currentIndex;

    newIndex = e.deltaY > 0 
      ? (currentIndex + 1) % routes.length 
      : (currentIndex - 1 + routes.length) % routes.length;

    navigate(routes[newIndex]);
  }, [location, navigate, routes]);

  useEffect(() => {
    window.addEventListener('wheel', handleNavigation);
    return () => window.removeEventListener('wheel', handleNavigation);
  }, [handleNavigation]); // 依赖更新后的handleNavigation

  return <>{children}</>;
}

解决方案2:实时获取当前路径(更简洁)

直接在事件触发时读取window.location.pathname,完全避开闭包带来的旧值问题:

const handleNavigation = (e) => {
  const currentPath = window.location.pathname;
  if (currentPath.startsWith('/work/')) {
    return;
  }

  const currentIndex = routes.findIndex(route => route === currentPath);
  let newIndex = currentIndex;

  newIndex = e.deltaY > 0 
    ? (currentIndex + 1) % routes.length 
    : (currentIndex - 1 + routes.length) % routes.length;

  navigate(routes[newIndex]);
};

关键说明

  • 之前调整useEffect依赖无效,是因为你只更新了useEffect的依赖,但handleNavigation函数本身没有重新创建,内部依然引用旧的location值。
  • 用startsWith('/work/')替代includes('/work/'),能避免误判包含work字段的非嵌套路由(比如/my-work)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:05:22