如何监听路由变化
在 React 中,监听路由变化通常使用路由库(如 react-router
)提供的钩子(如 useLocation()
)。但如果想手动监听原生浏览器路由变化,比如通过 popstate
、pushState
、replaceState
等方式实现监听,那就需要结合原生的 History API 来处理。
下面是一个完整的手动监听路由变化的方案:
关键点:
popstate
:浏览器原生的监听器,只能监听后退/前进按钮。pushState
/replaceState
:不会触发popstate
,需要手动劫持(monkey patch)它们来触发我们自己的事件。
实现思路:
- 劫持
history.pushState
和history.replaceState
,在它们执行时触发一个自定义事件。 - 监听
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()
来监听路由变化。 - 上述方法适用于需要监听低层路由变化(比如构建自己的路由库,或者需要做一些额外操作,比如统计、动画等)。