react-router中如何全局访问history,避免每个组件重复引入useHistory?
React Router全局访问history对象实现方案
为什么需要反复引入useHistory
这种设计是React和React Router的官方最佳实践,核心原因有2点:
- 依赖显式:Hooks的设计原则要求在组件内部显式声明依赖,方便代码维护和静态检查,你可以清晰地知道当前组件用到了哪些路由能力
- 避免全局污染:默认的
BrowserRouter内部会自己创建history实例,和当前Router上下文绑定,支持同一页面存在多个Router实例的场景,同时服务端渲染时不会出现跨请求的状态串扰问题
实现全局直接访问history的方案
方案1:自定义全局history实例(最常用,适用客户端渲染项目)
不需要每次在组件内调用useHistory,直接导出同一个history实例使用即可,操作步骤如下:
- 安装history依赖:
npm install history@4.x # React Router v5对应history 4.x版本,不要安装5.x以上版本
- 新建全局history文件,例如
src/utils/history.js:
import { createBrowserHistory } from 'history'; // 创建全局唯一的history实例 const history = createBrowserHistory(); export default history;
- 修改项目根组件的Router配置,将默认的
BrowserRouter替换为原生Router,传入自定义的history实例:
import { Router } from 'react-router-dom'; import history from './utils/history'; import App from './App'; ReactDOM.render( <Router history={history}> <App /> </Router>, document.getElementById('root') );
- 后续任意组件/JS文件都可以直接导入history使用,不需要再调用
useHistory:
import history from 'utils/history'; function HomeButton() { function handleClick() { history.push("/home"); } return ( <button type="button" onClick={handleClick}> Go home </button> ); }
注意:该方案仅推荐客户端渲染项目使用,服务端渲染项目使用会出现跨请求状态污染问题。如果你的项目使用React Router v6版本,
useHistory已经被useNavigate替代,对应的全局适配逻辑思路一致,替换对应API即可。
方案2:封装自定义Hooks(无副作用,符合官方规范)
如果你不想破坏React的设计规则,也可以把路由跳转逻辑封装为自定义Hooks,减少重复代码:
// src/hooks/useRouter.js import { useHistory } from 'react-router-dom'; export default function useRouter() { const history = useHistory(); return { push: history.push, replace: history.replace, goBack: history.goBack, goHome: () => history.push('/home'), // 可以自定义更多常用跳转方法 } }
组件内使用时只需要引入自定义Hooks即可,比反复引入useHistory更简洁:
import useRouter from 'hooks/useRouter'; function HomeButton() { const { push } = useRouter(); return ( <button type="button" onClick={() => push('/home')}> Go home </button> ); }
内容的提问来源于stack exchange,提问作者Fay Chen
相关产品推荐
相关产品推荐

