react-router-dom V5中受Hook规则限制如何正确使用history.push?
问题原因
你遇到的报错核心是违反React Hook调用规则:useHistory作为Hook,仅能在函数组件顶层、自定义Hook顶层调用,组件外、普通嵌套函数、非渲染流程中直接调用Hook都会抛出错误。
注意:你之前抽离
Redirect组件当普通函数执行的写法也不成立:React组件必须以JSX形式挂载到渲染树中才会生效,直接作为普通函数调用时,依然不在合法的Hook执行上下文里,还是会触发规则报错。
可行解决方案
方案1:组件内获取history传入handler(最小改动适配现有结构)
不需要调整现有handlers的对象结构,只需要在组件顶层合法获取history实例,作为参数传入跳转方法即可,改动成本最低:
// SomeFile.js import { useHistory } from "react-router-dom"; export const SomeFile = () => { // 符合Hook规则:函数组件顶层调用useHistory const history = useHistory(); console.log("something?"); // 将history实例传入handler handlers.SWITCH_PAGE(history); return null; }; const handlers = { // 接收传入的history实例完成跳转 SWITCH_PAGE: (history) => { try { console.log("triggered"); history.push({ pathname: "/someLocation" }); } catch (e) { console.error(e); } } }; export default SomeFile;
方案2:封装自定义Hook(符合React开发规范)
将关联的路由逻辑封装为自定义Hook(命名以use开头),在Hook内部合法调用useHistory,返回处理方法给组件使用,逻辑内聚性更强:
// SomeFile.js import { useHistory } from "react-router-dom"; // 自定义Hook封装跳转逻辑 const usePageHandlers = () => { const history = useHistory(); return { SWITCH_PAGE: () => { try { console.log("triggered"); history.push({ pathname: "/someLocation" }); } catch (e) { console.error(e); } } } } export const SomeFile = () => { // 组件顶层调用自定义Hook const handlers = usePageHandlers(); console.log("something?"); handlers.SWITCH_PAGE(); return null; }; export default SomeFile;
方案3:全局history实例(适配脱离组件的通用逻辑)
如果你的handlers是完全脱离组件的公共逻辑,可以创建独立的全局history实例,完全绕开Hook规则限制,在任意普通JS文件中都可以直接调用跳转:
- 安装依赖:执行命令
npm install history - 新建单独的history实例文件:
// src/history.js import { createBrowserHistory } from 'history'; export default createBrowserHistory();
- 修改根路由配置,替换原来的
BrowserRouter为原生Router,传入自定义的history实例:
// src/index.js import { Router } from "react-router-dom"; import history from "./history"; import App from "./App"; ReactDOM.render( <Router history={history}> <App /> </Router>, document.getElementById('root') );
- 业务代码中直接引入全局history使用,无需调用
useHistory:
// SomeFile.js import history from "./history"; export const SomeFile = () => { console.log("something?"); handlers.SWITCH_PAGE(); return null; }; const handlers = { SWITCH_PAGE: () => { try { console.log("triggered"); history.push({ pathname: "/someLocation" }); } catch (e) { console.error(e); } } }; export default SomeFile;
内容的提问来源于stack exchange,提问作者WeAreHawk09
相关产品推荐
相关产品推荐

