Is it possible to change route outside react function component and let react-router know about it?

Viewed 920

I'm using CRA (create-react-app) and react-router.

However, I also use an event-driven system to manage states and messaging.

Now I need to change URL somewhere outside react function components. Thus I can't use useHistory.

Is there a way to change the URL/Route and let react router know about it?

2 Answers

Create a function that will dispatch a Custom Event after clicking on the link. In the React application, implement an event listener for it and update the router's history.

 //Dispatch a custom event

 function changeRoute(path) {
    const { CustomEvent } = window;
    const event = new CustomEvent('changeroute', { detail: path });
    window.dispatchEvent(event);
 }

 //In the React App, listen for the event and update the router (instance of the BrowserRouter)

function handleRouteChange(router) {
     window.addEventListener('changeroute', e => {
           const { detail: path } = e;
           router.history.push(path);
     },true)
}

I don't think it's the official way to do this, but there is a trick I have been using for a while & it's working fine & bug-free.

you can define a component where you call useHistory (& all the other hooks you want to use outside functional components) in a useEffect & save them in a global out-hook object which then can be imported anywhere.

then you need to render that component on the initial render of your app, so you can make it a child of Router component in your main app.js file or wherever you're defining your routes.

so your outHookConfigurator would looke like this:

import {useHistory} from "react-router-dom";
import { useEffect } from "react";

const OutHook = {};

export const OutHookConfigurator = () => {
  const _useHistory = useHistory();

  useEffect(() => {
    OutHook.useHistory = _useHistory;
  }, [_useHistory]);


  return null;
};

export default OutHook;

then in your route app.js file you'd have:

<Router>
  <Switch>
    <OutHookConfigurator />
    <Route
      path="/example"
      component={Example}
    />
  </Switch>
</Router>

then, you would import the outhook object anywhere you want, and simply say:

outHook.useHistory.push()
Related