bukso
bukso

Reputation: 1376

How to navigate outside of react component using react router 6

Right now I have an History module, that let me use the history even outside of react component:

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

Then I use this history in App.jsx directly

import { Router } from 'react-router-dom';
...
<Router history={history}>...</Router>

I can import and use the same history object everywhere. Even in custom helpers outside of any react components.

How could this work in react router 6?

Since history is replaced with navigate, I don't see any solution yet online.

I know it is still beta, but I would like to check on it in advance.

Thanks for any ideas!

Upvotes: 22

Views: 10496

Answers (4)

Luka
Luka

Reputation: 1008

Inspired by @bukso, I ended up with the following solution in TypeScript.

global-history.tsx

import { useNavigate, NavigateFunction } from "react-router-dom";

export let globalNavigate: NavigateFunction;

export const GlobalHistory = () => {
  globalNavigate = useNavigate();

  return null;
};

index.tsx

<React.StrictMode>
  <BrowserRouter>
    <GlobalHistory />
    {/* ... */}
  </BrowserRouter>
</React.StrictMode>

Now, you're ready to use it outside React components. globalNavigate("profile")

Upvotes: 11

Joe Gasewicz
Joe Gasewicz

Reputation: 1485

Here is my solution, I wanted to navigate from the navbar back to the home page.

Create a HistoryRouter component & wrap your navbar or similar & then create react browser router separately for your routes.

import {createBrowserRouter, Link, unstable_HistoryRouter as HistoryRouter} from "react-router-dom";


export const history = createBrowserHistory({ window });

const App = () => {
    return (
       <>
          <HistoryRouter history={history}>
             <Navbar />
           </HistoryRouter>
          <RouterProvider router={router} />
       </>
    );
}

Then create a function that uses the history object to push the new path in the window's location.

import {history} from "../app";


export const logout = (to: string): void => {
    // e.g removeToken();
    history.push(to);
    window.location.reload();
};

I can now use the logout function in my navbar, for example:

<nav>
    <button onClick={_ => logout("/")}>Logout</button>
</nav>

Upvotes: 0

Martin Kadlec
Martin Kadlec

Reputation: 4975

In my case I needed access to the history object before first render, so I ended up writing custom component around Router based on the BrowserRouter implementation that would allow me to pass in history through props.

See https://github.com/remix-run/react-router/discussions/8241#discussioncomment-1677474 for code.

Edit: As of react-router-dom v6.1.0 HistoryRouter is part of its implementation so you can just directly do:

import {unstable_HistoryRouter as HistoryRouter} from 'react-router-dom'
import {createBrowserHistory} from 'history'

const history = createBrowserHistory()

<HistoryRouter history={history} />

Upvotes: 0

bukso
bukso

Reputation: 1376

I ended up with following solutions:

At first, react-router-dom 6 has navigate and not history. It is better to use navigate for the navigation trough the routes:

I create and fix my History object, so that it can continue work with 'push' and that I don't need big rework:

const History = {
  navigate: null,
  push: (page, ...rest) => History.navigate(page, ...rest),
};

export default History;

Then I made my own Component that set the navigation:

import { useNavigate } from 'react-router-dom';

const NavigateSetter = () => {
  History.navigate = useNavigate();

  return null;
};

Then while defining the default router, I place as a child the setter:

import { BrowserRouter } from 'react-router-dom';

<BrowserRouter>
    <NavigateSetter />
    <App />
</BrowserRouter>

After that you can use everywhere History.push or History.navigate with the default react-router-dom's navigate API.

Upvotes: 23

Related Questions