172

I am new to React Router and learn that there are so many ways to redirect a page:

  1. Using browserHistory.push("/path")

    import { browserHistory } from 'react-router';
    //do something...
    browserHistory.push("/path");
    
  2. Using this.context.router.push("/path")

    class Foo extends React.Component {
        constructor(props, context) {
            super(props, context);
            //do something...
        }
        redirect() {
            this.context.router.push("/path")
        }
    }
    
    Foo.contextTypes = {
        router: React.PropTypes.object
    }
    
  3. In React Router v4, there's this.context.history.push("/path") and this.props.history.push("/path"). Details: How to push to History in React Router v4?

I'm so confused by all these options, is there a best way to redirect a page?

Liutong Chen
  • 2,915
  • 5
  • 22
  • 29

5 Answers5

273

Actually it depends on your use case.

1) You want to protect your route from unauthorized users

If that is the case you can use the component called <Redirect /> and can implement the following logic:

import React from 'react'
import  { Redirect } from 'react-router-dom'

const ProtectedComponent = () => {
  if (authFails)
    return <Redirect to='/login'  />
  }
  return <div> My Protected Component </div>
}

Keep in mind that if you want <Redirect /> to work the way you expect, you should place it inside of your component's render method so that it should eventually be considered as a DOM element, otherwise it won't work.

2) You want to redirect after a certain action (let's say after creating an item)

In that case you can use history:

myFunction() {
  addSomeStuff(data).then(() => {
      this.props.history.push('/path')
    }).catch((error) => {
      console.log(error)
    })

or

myFunction() {
  addSomeStuff()
  this.props.history.push('/path')
}

In order to have access to history, you can wrap your component with an HOC called withRouter. When you wrap your component with it, it passes match location and history props. For more detail please have a look at the official documentation for withRouter.

If your component is a child of a <Route /> component, i.e. if it is something like <Route path='/path' component={myComponent} />, you don't have to wrap your component with withRouter, because <Route /> passes match, location, and history to its child.

3) Redirect after clicking some element

There are two options here. You can use history.push() by passing it to an onClick event:

<div onClick={this.props.history.push('/path')}> some stuff </div>

or you can use a <Link /> component:

 <Link to='/path' > some stuff </Link>

I think the rule of thumb with this case is to try to use <Link /> first, I suppose especially because of performance.

Mihai Chelaru
  • 7,614
  • 14
  • 45
  • 51
Cagri Yardimci
  • 3,479
  • 1
  • 11
  • 15
  • It's working for me ` this.props.history.push("/");` **React-router--v4.2** Thanks @Cagri – MD Ashik Jan 25 '18 at 19:20
  • https://stackoverflow.com/questions/60579292/redirection-not-working-because-of-order-of-executions-of-functions/60579404?noredirect=1#comment107174072_60579404 Could you please have a look at this qs? –  Mar 07 '20 at 16:17
  • In the last option, because the component has `history` in its props to be able to do `this.props.history.push('/path')`, it means that component is a child of `` or it has `withRouter` wrapper in export correct? – Andre May 14 '20 at 10:35
  • So it is possible to route to another component without specifying ``, I guess just plain `render() { return }` in a condition? – Andre May 14 '20 at 10:43
  • @Andre yep that's correct for the use of `this.props.history` however I am not sure if I got your second question correct? What do you exactly mean by `route to another component`? – Cagri Yardimci May 14 '20 at 11:11
  • @CagriYardimci Thanks. Also in that 3rd option, shouldn't the `onClick` have an arrow function with the `history.push` to prevent it from calling prematurely? – Andre May 14 '20 at 11:16
  • @Andre probably, but the code I provided mostly made up to just provide some alternatives :) So you might need to adjust a bit to make it work – Cagri Yardimci May 14 '20 at 11:45
  • The method this.props.history.push('/path') almost worked perfectly for me. Problem is that, I suspect that it loads a page from some kind of cache, as I had visited the page, and the query I sent, should make the page look different, but it didn´t. Any additional solution on this? – Jorge Mauricio Jun 30 '21 at 16:25
  • 1
    Note that in step 1, in the release of React Router v6, the `Redirect` component was removed and replaced with the `Navigate` component – Prav Aug 18 '22 at 17:59
28

You can also use react router dom library useHistory;

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

function HomeButton() {
  let history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

https://reactrouter.com/web/api/Hooks/usehistory

Bhavik Parmar
  • 424
  • 1
  • 6
  • 9
Maya Liberman
  • 328
  • 3
  • 5
16

Now with react-router v15.1 and onwards we can useHistory hook, This is super simple and clear way. Here is a simple example from the source blog.

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

function BackButton({ children }) {
  let history = useHistory()
  return (
    <button type="button" onClick={() => history.goBack()}>
      {children}
    </button>
  )
}

You can use this within any functional component and custom hooks. And yes this will not work with class components same as any other hook.

Learn more about this here https://reacttraining.com/blog/react-router-v5-1/#usehistory

Anand Singh
  • 2,343
  • 1
  • 22
  • 34
2

You also can Redirect within the Route as follows. This is for handle invalid routes.

<Route path='*' render={() => 
     (
       <Redirect to="/error"/>
     )
}/>
Pramuditha
  • 638
  • 6
  • 8
0

One of the simplest way: use Link as follows:

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

<Link to={`your-path`} activeClassName="current">{your-link-name}</Link>

If we want to cover the whole div section as link:

 <div>
     <Card as={Link} to={'path-name'}>
         .... 
           card content here
         ....
     </Card>
 </div>

RameshD
  • 912
  • 7
  • 6
  • Where did you get your `Card` component from? Looks promising but pls show more context for your answer – Beast Jan 25 '23 at 08:17
  • 1
    `Card` here could be either react material ui card component or it could be custom UI component created. eg. import Card from '@mui/material/Card'; – RameshD Feb 06 '23 at 05:48