loading...
Cover image for Programmatic Navigation in React using react-router

React Router Redirect Programmatic Navigation in React using react-router

projectescape profile image Aniket Updated on ・3 min read

I have seen my fair share of react tutorials, but any time that they talk about navigation using react-router, they only show the way using the Link component. As soon as someone starts working on his/her own project, one of the first problems they come across is how to route programmatically, which basically means routing with ways other than clicking on something wrapped inside a <Link> component.
This blog mainly aims to be a refuge to those people who come here looking for the answers to this problem.


1. <Redirect> Component

We can redirect using <Redirect> component by simply passing the route we want to redirect to and rendering the component. It already comes loaded in the react-router-dom library.

import { Redirect } from "react-router-dom";

The easiest way to use this method is by maintaining a redirect property inside the state of the component.

state = { redirect: null };
render() {
  if (this.state.redirect) {
    return <Redirect to={this.state.redirect} />
  }
  return(
  // Your Code goes here
  )
}

Whenever you want to redirect to another path, you can simply change the state to re-render the component, thus rendering the <Redirect> component.

this.setState({ redirect: "/someRoute" });

Note
This is the recommended way to navigate other than the <Link> method.
Discussed in detail towards the end of the post.

The downside of this method is that in cases like when we want to redirect directly from a redux action, we cannot do so.


2. useHistory Hook

As of release 5.1.2, react-router ships with some new hooks that can help us access the state of the router.

For now, we only need to talk about the useHistory hook.

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

function App() {
  let history = useHistory();
}

After this, we can use the .push() method to redirect to any route we want.

history.push('/someRoute')

3. History prop

Every component that is an immediate child of the <Route> component receives history object as a prop. This is the same history (library) which keeps history of the session of React Router. We can thus use its properties to navigate to the required paths.

this.props.history.push("/first");

A common problem that we can encounter here is that in components which are not an immediate child to the <Route> component, there is no history prop present. This can be easily solved using the withRouter function.

3.1. withRouter

withRouter is a function provided in the react-router-dom library that helps us access the history prop in components which are not immediate children to the <Route> components.
To import withRouter

import { withRouter } from "react-router-dom";

Now to get the history prop inside our component, we need to wrap our component with withRouter while exporting it.

export default withRouter(yourComponent);

We can now access the history prop same as above to do our required navigations.


4. createHistory

The methods we learned above can cover most of the cases that we'll ever encounter while building a react app, so why this fourth method?
Every time we need to redirect from, say as an example a redux action, we always have to pass history to the action, unnecessarily increasing the number of arguments. This method can thus be used to get a neater code.

In this method, we make our custom history instance which we can import in other files to redirect.

// Inside /utils/history.js
import createHistory from "history/createBrowserHistory";
export default createHistory();

As <BrowserRouter> uses its own history and does not accept any outer history property, we have to use <Router> instead of it.

import { Router } from "react-router-dom";
import history from "./utils/history";

function App(){
  return(
    <Router history={history}>
    // Your Routes go here
    <Router>
  )
}

After this, we can import this history instance in whichever file we want to redirect from.

import history from "./utils/history";

history.push("/somePath");

NOTE

At its core, React is a declarative approach to building UIs.

Declarative approach is one where we express the logic of a computation without describing its control flow, or without describing what's actually happening behind the scenes.

Due to this reason, the recommended way to navigate other than <Link> is using <Redirect> component.

There is no harm in using the other methods mentioned here, just that they don't exactly align with React's vision.


Repository

A fully working implementation of the above methods is available on my Github profile. Feel free to explore it if anyone wants to see these methods actually working in a project.

GitHub logo projectescape / blogs-reference

A repository which contains the source complementing all the blogs I write


Discussion

pic
Editor guide
Collapse
rusikf profile image
Ruslan Korolev

The last way - add utils/history, add this to BrowserRouter + trying to use this constant in redux action doesnt work. It changes url, but react-router don't render component
Looks, the problem because we create 2 instances of createHistory, Details - github.com/ReactTraining/react-rou...

Other ways works, thanks for article!

Collapse
projectescape profile image
Aniket Author

Glad you liked it. But you sure the last way is not working? I'm positive it was working when I wrote this post, I also linked my repo which has the code I wrote back then. I have used Router instead of BrowserRouter, as BrowserRouter comes with its own history

Collapse
rusikf profile image
Ruslan Korolev

Amazing, it works when I tried to use Router! Thanks a lot !!

Collapse
wintercounter profile image
Victor Vincent

The article completely misses the hooks way (useRouter).

You should stick to the declerative way whenever you can. I think the article should endorse this to be complete.

Collapse
dance2die profile image
Sung M. Kim
  1. You should not redirect from a Redux action. Actions should not have side-effects.

Would checking for a Redux state and redirect on state change/value be a good way?

Collapse
wintercounter profile image
Victor Vincent

I updated my comment as it was bs :) For some reason I had reducers in my mind all along.

Collapse
kustomdesigner profile image
Michael Hicks

Any negative effects from redirecting using local state?

Collapse
projectescape profile image
Aniket Author

Thanks for the comment.
I'll try to update the article as soon as I can.

Collapse
projectescape profile image
Aniket Author

I've updated the post, would really appreciate if you check it out!

Collapse
wintercounter profile image
Collapse
webcoderkz profile image
Alexander Kim

So, react-router team is preferring <Redirect to="/asd/" /> component over imperative style history.push('/asd'). But, sometimes is just easier to use history.push() instead of rendering a redirect component. What's your thoughts?

Collapse
projectescape profile image
Aniket Author

I think it's the same as using hooks and functional components over class based components.
Although it's recommended, it's better to just stick to whatever you and your team is more comfortable with and what makes more sense to you.
In the end writing code that actually works and which you can easily understand later to further iterate is more important.

Collapse
alsmith808 profile image
Alan Smith

Thank you, useHistory() works great for me, so simple, brilliant!!

Collapse
shamxeed profile image
Musa Danjuma

Hi thanks for taking the time to post this but please I'm having an issue. I tried the first approach as recommended by you but the component I'm redirecting to is not displaying but the path in the URL will change. Any idea on how to fix that, please?

Note: If I redirect to the homepage it will work but to other paths is not.

Collapse
josesimancas51 profile image
José Simancas

Exelent bro, this helped me!

Collapse
kustomdesigner profile image
Michael Hicks

Thank you, useHistory Hook was exactly what I needed.