Estoy usando react-router-dom v6 y mobex en mi proyecto y obtengo un error cuando lo uso como se muestra a continuación.
principal.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' import { BrowserRouter } from 'react-router-dom' import { useNavigate } from 'react-router-dom'; export const navigate = useNavigate(); ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <StoreContext.Provider value={store}> <BrowserRouter> <App /> </BrowserRouter> </StoreContext.Provider> </React.StrictMode> )usuarioStore.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 { navigate } 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; navigate('/'); } }Error:
"Invalid hook call. Hooks can only be called inside the body of a function component"En la versión anterior funcionaba cuando lo hice así a continuación:
principal.tsx:
... ... import { createBrowserHistory } from "history"; export const history = createBrowserHistory(); ... ...y userStore.tsx:
import { makeAutoObservable, runInAction } from "mobx"; import agent from "../api/agent"; import { User, UserFormValues } from "../models/user"; import { store } from "./store"; import { history } from "../../index"; 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("/"); };¿Como puedó resolver esté problema?
Esta línea const navigate = useNavigate() solo puede estar dentro de un componente de React o un gancho personalizado, ya que useNavigate es un gancho. Ver Reglas de Hooks para saber más. Una forma de resolver esto es cambiar su función de logout de sesión para que tome navigate como parámetro, así:
logout = (navigate) => { store.commonStore.setToken(null); window.localStorage.removeItem("jwt"); this.user = null; navigate("/"); }; Y llame a useNavigate en el componente donde llama a logout y le da navigate como parámetro. Así como un ejemplo:
import UserStore from "./UserStore"; // use the correct path import { useNavigate } from "react-router-dom"; export default function Component() { const navigate = useNavigate(); const userStore = UserStore(); userStore.logout(navigate); return <div></div>; } Los ganchos de React solo se pueden usar dentro de un componente de función de React y el gancho useNavigate solo se puede usar dentro de un contexto de enrutamiento.
Acceda a la función de navigate a través del useNavigate desde un componente de la función React y pase una referencia para navigate al controlador de logout de sesión.
logout = ({ navigate }) => { store.commonStore.setToken(null); window.localStorage.removeItem("jwt"); this.user = null; navigate("/"); };...
const SomeComponent = () => { const navigate = useNavigate(); ... UserStore.logout({ navigate }); ... }; Importe y use elHistoryRouter y continúe usando el objeto de history personalizado como antes. Esto requiere la dependencia del paquete history@5 , instálelo si es necesario ( ejecute npm i -S history@5 ).
Ejemplo:
Crear y exportar objeto de history .
import { createBrowserHistory } from "history"; export const history = createBrowserHistory();...
... import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom'; import { history } from '../path/to/history'; ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <StoreContext.Provider value={store}> <HistoryRouter history={history}> <App /> </HistoryRouter> </StoreContext.Provider> </React.StrictMode> ); UserStore continúa importando el objeto de history y usándolo.
import { makeAutoObservable, runInAction } from "mobx"; import agent from "../api/agent"; import { User, UserFormValues } from "../models/user"; import { store } from "./store"; import { history } from "../path/to/history"; 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("/"); }; ...No puede usar ganchos en el componente de clase. para la ruta a través del componente de clase, hay otra forma de hacerlo. pero creo que en el enrutador 6 se elimina el soporte de componentes de clase. para que pueda cambiar su componente de clase a componente de función, es una manera fácil.