En react-router v5 creé un objeto de historial como este:
import { createBrowserHistory } from "history"; export const history = createBrowserHistory();Y luego lo pasó al enrutador:
import { Router, Switch, Route, Link } from "react-router-dom"; <Router history={history}> ... my routes </Router>Lo hice por la oportunidad de usar el historial fuera del componente:
// store action logout() { this.user = null; history.push('/'); } De esta manera moví la lógica a la tienda y los componentes se mantuvieron lo más limpios posible. Pero ahora, en el enrutador de reacción v6, no puedo hacer lo mismo. Todavía puedo navegar usando useNavigate() dentro de mi componente, pero no puedo crear una navigate para usarla en mi tienda. ¿Hay alguna alternativa?
Bueno, resulta que puede duplicar el comportamiento si implementa un enrutador personalizado que instancia el estado del historial de la misma manera que los enrutadores RRDv6.
Examine la implementación de BrowserRouter , por ejemplo:
export function BrowserRouter({ basename, children, window }: BrowserRouterProps) { let historyRef = React.useRef<BrowserHistory>(); if (historyRef.current == null) { historyRef.current = createBrowserHistory({ window }); } let history = historyRef.current; let [state, setState] = React.useState({ action: history.action, location: history.location }); React.useLayoutEffect(() => history.listen(setState), [history]); return ( <Router basename={basename} children={children} location={state.location} navigationType={state.action} navigator={history} /> ); }
Cree un CustomRouter que consuma un objeto de history personalizado y administre el estado:
const CustomRouter = ({ history, ...props }) => { const [state, setState] = useState({ action: history.action, location: history.location }); useLayoutEffect(() => history.listen(setState), [history]); return ( <Router {...props} location={state.location} navigationType={state.action} navigator={history} /> ); }; Esto envía de manera efectiva el objeto de history personalizado al Router y administra el estado de navegación.
Desde aquí, intercambia CustomRouter con un objeto de history personalizado para el Router existente importado de react-router-dom .
export default function App() { return ( <CustomRouter history={history}> <div className="App"> <Routes> <Route path="/" element={<Home />} /> <Route path="/profile" element={<Profile />} /> </Routes> </div> </CustomRouter> ); }Bifurcación de su codesandbox:
Solución de TypeScript de respuesta aceptada
objeto de la historia:
import { createBrowserHistory } from "history"; const customHistory = createBrowserHistory(); export default customHistory;BrowserRouterProps es un tipo de enrutador de reacción.
export interface BrowserRouterProps { basename?: string; children?: React.ReactNode; window?: Window; }
Enrutador personalizado:
import { useLayoutEffect, useState } from "react"; import { BrowserRouterProps, Router } from "react-router-dom"; import { BrowserHistory } from "history"; import customHistory from "./history"; interface Props extends BrowserRouterProps { history: BrowserHistory; } export const CustomRouter = ({ basename, history, children }: Props) => { const [state, setState] = useState({ action: history.action, location: history.location, }); useLayoutEffect(() => history.listen(setState), [history]); return ( <Router navigator={customHistory} location={state.location} navigationType={state.action} children={children} basename={basename} /> ); };use CustomRouter en lugar de BrowserRouter
ReactDOM.render( <React.StrictMode> <CustomRouter history={customHistory}> <App /> </CustomRouter> </React.StrictMode>, document.getElementById("root") );