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

React Router Dom返回导航实现报错:A history only accepts one active listener

解决react-router-dom返回导航报错:A history only accepts one active listener

问题原因

你使用了UNSAFE_NavigationContext直接注册导航监听器,而react-router-dom内部已经维护了一个导航监听器。这个私有API限制同一时间只能有一个活跃监听器,因此触发了冲突报错。另外,带UNSAFE_前缀的API属于内部私有接口,官方不推荐使用,后续版本可能会被修改或移除。

修复方案

改用react-router-dom官方提供的useLocation和useNavigationType钩子追踪导航状态,替代直接监听navigator的方式,既安全又不会触发监听器冲突。

修改后的代码

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState
} from "react";
import {
  useNavigate as useNavigateBase,
  useLocation,
  useNavigationType
} from "react-router-dom";

export const NavigateContext = createContext({
  navigate: () => {}
});

export const useNavigate = () => useContext(NavigateContext);

// eslint-disable-next-line react/prop-types
const NavigateProvider = ({ children }) => {
  const [historyStack, setHistoryStack] = useState([]);
  const navigate = useNavigateBase();
  const location = useLocation();
  const navigationType = useNavigationType();

  useEffect(() => {
    switch (navigationType) {
      case "PUSH":
        setHistoryStack(prev => [...prev, location]);
        break;
      case "REPLACE":
        setHistoryStack(prev => [...prev.slice(0, -1), location]);
        break;
      case "POP":
        setHistoryStack(prev => prev.slice(0, -1));
        break;
      default:
        // 忽略其他情况
    }
  }, [location, navigationType]);

  useEffect(() => {
    console.log({ historyStack });
  }, [historyStack]);

  const navigateHandler = useCallback(
    (arg, options) => {
      if (typeof arg === "number" && arg < 0 && historyStack.length === 0) {
        navigate("/", { replace: true });
      } else {
        navigate(arg, options);
      }
    },
    [historyStack, navigate]
  );

  return (
    <NavigateContext.Provider value={{ navigate: navigateHandler }}>
      {children}
    </NavigateContext.Provider>
  );
};

export default NavigateProvider;

关键改动说明

  • 移除对UNSAFE_NavigationContext的依赖,改用useLocation获取当前路由地址,useNavigationType获取导航类型(PUSH/REPLACE/POP)。
  • 通过监听location和navigationType的变化更新历史栈,逻辑和原代码一致,但避免了直接操作navigator引发的监听器冲突。
  • 保留原有自定义导航逻辑,确保历史栈为空时返回主页的功能正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:10:18