如何重写React-Router-Dom v5的History.push方法自动添加哈希参数?
在React Router v5中直接重写history.push自动附加哈希查询参数
问题描述
我希望调用history.push导航时,自动把查询字符串的哈希值附加到URL里。目前我写了一个自定义hook返回增强版的pusher函数,但需要在多处替换history.push为这个自定义函数,请问能不能直接重写history.push方法?我用的是react-router-dom v5版本。
现有代码:
let pusher: null | ((a: unknown, b?: unknown) => void) = null; /** * This hook will push a hashed value of query string of the url * * Don't mind about memory leak, it's `Singletom` * @param history an instance of History from useHistory * @returns `Pusher` an enhance version of `History.push` */ export default function useHashPusher(history: ReturnType<typeof useHistory>){ const sha256 = useSha256(); if(!pusher) { pusher = function(...args) { const data = args[0]; if(typeof data === 'object' && data && 'search' in data){ const raw = data['search' as keyof typeof data]; if(raw){ const hashed = sha256.hash(raw); (data['search' as keyof typeof data] as string) = `${raw}&hash=${hashed}`; console.log(data); } } console.log('overrided!', args[0]); history.push(...args); }; } return pusher; }
解决方案
当然可以直接重写history.push方法,只需在hook中保存原始push方法,用自定义逻辑包装后替换原方法即可,这样全局调用history.push都会自动应用哈希附加逻辑,无需逐一替换。
实现代码
import { useHistory } from 'react-router-dom'; import useSha256 from './your-sha256-hook-path'; // 替换为你的useSha256实际路径 export default function useOverrideHistoryPush() { const history = useHistory(); const sha256 = useSha256(); // 仅执行一次重写,避免重复包装 const originalPush = history.push; if (history.push !== originalPush) return; history.push = function(...args) { const [data, state] = args; let modifiedData = data; // 处理对象形式的路径参数 if (typeof data === 'object' && data && 'search' in data) { const rawSearch = data.search as string; if (rawSearch) { const hashed = sha256.hash(rawSearch); // 创建新对象而非修改原对象,避免副作用 modifiedData = { ...data, search: `${rawSearch}&hash=${hashed}` }; } } // 处理字符串形式的路径参数(如'/page?foo=bar') else if (typeof data === 'string') { const [pathname, search] = data.split('?'); if (search) { const hashed = sha256.hash(search); modifiedData = `${pathname}?${search}&hash=${hashed}`; } } // 调用原始push方法,保持原有行为 return originalPush.call(history, modifiedData, state); }; // 可选:组件卸载时恢复原始push方法,避免影响其他组件场景 // useEffect(() => { // return () => { // history.push = originalPush; // }; // }, [history, originalPush]); }
使用方法
在应用根组件(如App.tsx)中调用该hook,全局生效:
import useOverrideHistoryPush from './useOverrideHistoryPush'; function App() { useOverrideHistoryPush(); return ( {/* 你的路由结构 */} ); }
注意要点
- 新增了字符串形式路径的处理逻辑,覆盖
history.push的所有调用场景,比原有代码更全面。 - 采用创建新对象的方式修改参数,避免直接修改传入对象带来的意外副作用。
- 若需在组件卸载后恢复原始
push方法,可取消注释代码中的useEffect部分;如果是全局唯一调用,也可忽略该处理。
内容的提问来源于stack exchange,提问作者Hao.Le
相关产品推荐
相关产品推荐

