React-Router-Dom v6结合Mobx时useNavigate调用报错问题求助
问题原因
你直接在main.tsx的顶层作用域调用useNavigate(),违反了React Hook的核心规则:Hook只能在函数组件的主体内部或自定义Hook中调用,因此触发了"Invalid hook call"错误。
解决方案
方案1:继续使用history对象(适配React Router v6,改动最小)
React Router v6的BrowserRouter默认内部管理history,但你可以通过Router组件手动传入自定义的history实例,延续旧版本的用法:
- 确保安装
history包:
npm install history
- 修改
main.tsx:
import React from 'react' import ReactDOM from 'react-dom/client' import App from './app/layout/App' import './app/layout/styles.css' import 'semantic-ui-css/semantic.min.css' import 'react-toastify/dist/ReactToastify.min.css' import 'react-calendar/dist/Calendar.css' import 'react-datepicker/dist/react-datepicker.css' import { store, StoreContext } from './app/stores/store' // 替换BrowserRouter为Router,引入createBrowserHistory import { Router } from 'react-router-dom' import { createBrowserHistory } from 'history' export const history = createBrowserHistory() ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <StoreContext.Provider value={store}> {/* 传入自定义history实例 */} <Router location={history.location} navigator={history}> <App /> </Router> </StoreContext.Provider> </React.StrictMode> )
- 修改
userStore.ts(和旧版本用法完全一致):
import { UserFormValues } from './../models/user'; import { makeAutoObservable, runInAction } from "mobx"; import { User } from "../models/user"; import agent from '../api/agent'; import { store } from './store'; import { history } from '../../main'; export default class UserStore { user: User | null = null; constructor() { makeAutoObservable(this); } logout = () => { store.commonStore.setToken(null); window.localStorage.removeItem('jwt'); this.user = null; history.push('/'); } }
方案2:向Store注入navigate函数(符合v6的Hook设计)
如果不想依赖history包,可以在根组件中获取navigate并注入到Store中:
- 修改
main.tsx,添加包装组件获取navigate:
import React from 'react' import ReactDOM from 'react-dom/client' import App from './app/layout/App' import './app/layout/styles.css' import 'semantic-ui-css/semantic.min.css' import 'react-toastify/dist/ReactToastify.min.css' import 'react-calendar/dist/Calendar.css' import 'react-datepicker/dist/react-datepicker.css' import { store, StoreContext } from './app/stores/store' import { BrowserRouter, useNavigate } from 'react-router-dom' // 包装组件:获取navigate并注入Store const AppWrapper = () => { const navigate = useNavigate(); React.useEffect(() => { store.setNavigate(navigate); }, [navigate]); return <App />; } ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <StoreContext.Provider value={store}> <BrowserRouter> <AppWrapper /> </BrowserRouter> </StoreContext.Provider> </React.StrictMode> )
- 更新
store.ts,添加存储navigate的属性和方法:
import UserStore from './userStore'; import CommonStore from './commonStore'; import { NavigateFunction } from 'react-router-dom'; class RootStore { userStore: UserStore; commonStore: CommonStore; navigate?: NavigateFunction; constructor() { this.userStore = new UserStore(this); this.commonStore = new CommonStore(this); } setNavigate = (navigate: NavigateFunction) => { this.navigate = navigate; } } export const store = new RootStore(); export const StoreContext = React.createContext(store);
- 修改
userStore.ts,通过RootStore调用navigate:
import { UserFormValues } from './../models/user'; import { makeAutoObservable, runInAction } from "mobx"; import { User } from "../models/user"; import agent from '../api/agent'; import { RootStore } from './store'; export default class UserStore { user: User | null = null; private rootStore: RootStore; constructor(rootStore: RootStore) { makeAutoObservable(this); this.rootStore = rootStore; } logout = () => { this.rootStore.commonStore.setToken(null); window.localStorage.removeItem('jwt'); this.user = null; this.rootStore.navigate?.('/'); } }
内容的提问来源于stack exchange,提问作者erhanbasturk
相关产品推荐
相关产品推荐

