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
相关产品推荐
相关产品推荐

