Skip to content

如何监听路由变化

在 React 中,监听路由变化通常使用路由库(如 react-router)提供的钩子(如 useLocation())。但如果想手动监听原生浏览器路由变化,比如通过 popstatepushStatereplaceState 等方式实现监听,那就需要结合原生的 History API 来处理。

下面是一个完整的手动监听路由变化的方案:

关键点:

  • popstate:浏览器原生的监听器,只能监听后退/前进按钮。
  • pushState / replaceState:不会触发 popstate,需要手动劫持(monkey patch)它们来触发我们自己的事件。

实现思路:

  1. 劫持 history.pushStatehistory.replaceState,在它们执行时触发一个自定义事件。
  2. 监听 popstate 和我们自定义的事件。

示例代码(React 组件中使用)

tsx
import { useEffect } from 'react';

function useManualRouteListener(callback: (path: string) => void) {
  useEffect(() => {
    const triggerCallback = () => callback(window.location.pathname);

    // 劫持 pushState
    const originalPushState = history.pushState;
    history.pushState = function (...args) {
      originalPushState.apply(history, args);
      window.dispatchEvent(new Event('custom-pushstate'));
    };

    // 劫持 replaceState
    const originalReplaceState = history.replaceState;
    history.replaceState = function (...args) {
      originalReplaceState.apply(history, args);
      window.dispatchEvent(new Event('custom-replacestate'));
    };

    // 监听 popstate + 自定义事件
    window.addEventListener('popstate', triggerCallback);
    window.addEventListener('custom-pushstate', triggerCallback);
    window.addEventListener('custom-replacestate', triggerCallback);

    // 初始触发一次
    triggerCallback();

    return () => {
      history.pushState = originalPushState;
      history.replaceState = originalReplaceState;
      window.removeEventListener('popstate', triggerCallback);
      window.removeEventListener('custom-pushstate', triggerCallback);
      window.removeEventListener('custom-replacestate', triggerCallback);
    };
  }, [callback]);
}

使用方法:

tsx
function App() {
  useManualRouteListener((path) => {
    console.log('Route changed to:', path);
  });

  return <div>My App</div>;
}

💡注意事项:

  • 如果用的是 react-router,建议优先使用 useLocation() 来监听路由变化。
  • 上述方法适用于需要监听低层路由变化(比如构建自己的路由库,或者需要做一些额外操作,比如统计、动画等)。