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

如何修复react-router-dom v6中withRouter的listen功能失效问题

解决方案

问题核心在于用useState存储回调函数会在组件重渲染时丢失引用,且useState更新会触发不必要的重渲染。改用useRef持久化存储回调引用,同时完善listen的API兼容性,即可解决问题。

修改后的withRouter包装器代码

import * as React from 'react';
import { useLocation, useNavigate, useNavigationType, useParams } from "react-router";

export function withRouter(Child) {
  return (props) => {
    // 用useRef存储回调引用,持久化保存不会因重渲染丢失
    const callBackRef = React.useRef();
    const location = useLocation();
    const navigate = useNavigate();
    const action = useNavigationType();
    const params = useParams();
    const match = {
      params: params
    };

    const history = {
      push: (url, onMount) => {
        if (onMount) {
          setTimeout(() => navigate(url), 100);
        } else {
          navigate(url);
        }
      },
      listen: (callback) => {
        // 更新ref的current属性,无需触发组件重渲染
        callBackRef.current = callback;
        // 返回取消监听的函数,对齐v5的API规范
        return () => {
          callBackRef.current = undefined;
        };
      }
    };

    React.useEffect(() => {
      // 当location或action变化时,调用最新的回调
      if (callBackRef.current) {
        callBackRef.current(location, action);
      }
    }, [location, action]); // 加入action依赖,对齐v5的监听逻辑

    return <Child {...props} history={history} location={location} match={match} />;
  };
}

关键修改说明

  1. 用useRef替代useState存储回调:useRef的.current属性在组件整个生命周期内保持引用,不会因组件重渲染被重置,彻底解决callBack变为undefined的问题,同时不会触发不必要的重渲染。
  2. 补充取消监听的返回函数:符合react-router-dom v5中history.listen的API规范,允许组件在卸载时清理监听,避免内存泄漏。
  3. 调整useEffect依赖:加入action参数,确保路由动作(如PUSH、POP)变化时也能触发回调,和v5的行为保持一致。

类组件的配套优化

为了避免重复监听和内存泄漏,建议在类组件中添加监听的清理逻辑:

componentDidMount(): void {
  // 保存取消监听的函数
  this.unlisten = this.props.history.listen((location, action) => {
    const urlSearchParams = new URLSearchParams(window.location.search);
    const params = Object.fromEntries(urlSearchParams.entries());
    if (params.id) {
      this.setState({id: params.id});
    }
  });
  this.getNotification();
  Utils.scrollToTop();
}

componentWillUnmount(): void {
  // 组件卸载时取消监听
  if (this.unlisten) {
    this.unlisten();
  }
}

// 可选:如果history对象发生变化,重新设置监听
componentDidUpdate(prevProps): void {
  if (prevProps.history !== this.props.history) {
    if (this.unlisten) {
      this.unlisten();
    }
    this.unlisten = this.props.history.listen((location, action) => {
      const urlSearchParams = new URLSearchParams(window.location.search);
      const params = Object.fromEntries(urlSearchParams.entries());
      if (params.id) {
        this.setState({id: params.id});
      }
    });
  }
}

内容的提问来源于stack exchange,提问作者Majid M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:20:43