179

I am trying to do A SIMPLE thing using react-router ( version ^1.0.3 ) to redirect to another view.

import React from 'react';
import {Router, Route, Link, RouteHandler} from 'react-router';


class HomeSection extends React.Component {

  static contextTypes = {
    router: PropTypes.func.isRequired
  };

  constructor(props, context) {
    super(props, context);
  }

  handleClick = () => {
    console.log('HERE!', this.contextTypes);
    // this.context.location.transitionTo('login');
  };

  render() {
    return (
      <Grid>
        <Row className="text-center">          
          <Col md={12} xs={12}>
            <div className="input-group">
              <span className="input-group-btn">
                <button onClick={this.handleClick} type="button">
                </button>
              </span>
            </div>
          </Col>
        </Row>
      </Grid>
    );
  }
};

HomeSection.contextTypes = {
  location() {
    React.PropTypes.func.isRequired
  }
}

export default HomeSection;

all I need is to send the user to '/login' and that's it.

What can I do ?

errors in console:

Uncaught ReferenceError: PropTypes is not defined

file with my routes

// LIBRARY
/*eslint-disable no-unused-vars*/
import React from 'react';
/*eslint-enable no-unused-vars*/
import {Route, IndexRoute} from 'react-router';

// COMPONENT
import Application from './components/App/App';
import Contact from './components/ContactSection/Contact';
import HomeSection from './components/HomeSection/HomeSection';
import NotFoundSection from './components/NotFoundSection/NotFoundSection';
import TodoSection from './components/TodoSection/TodoSection';
import LoginForm from './components/LoginForm/LoginForm';
import SignupForm from './components/SignupForm/SignupForm';

export default (
    <Route component={Application} path='/'>
      <IndexRoute component={HomeSection} />
      <Route component={HomeSection} path='home' />
      <Route component={TodoSection} path='todo' />
      <Route component={Contact} path='contact' />
      <Route component={LoginForm} path='login' />
      <Route component={SignupForm} path='signup' />
      <Route component={NotFoundSection} path='*' />
    </Route>
);
Reacting
  • 5,543
  • 7
  • 35
  • 86
  • Hi! Can you post your `routes` definitions, and also if there is reason you are not using `Link` component? Also, mention what errors you getting. – aarosil Jan 12 '16 at 04:31
  • Instead of button , `Log In`? – aarosil Jan 12 '16 at 04:33
  • Also what version of react-router are you using? The code for procedurally redirecting has changed among the major versions. – mjhm Jan 12 '16 at 04:36
  • @mjhm "react-router": "^1.0.3" – Reacting Jan 12 '16 at 04:37
  • 4
    For the `Uncaught ReferenceError`, you are calling as `PropTypes`, but you don't import that, you need import PropTypes as itself or use `React.PropTypes` – aarosil Jan 12 '16 at 04:37
  • Also `RouteHandler` not used in `react-router@1.0x`, you just use `this.props.children` instead. Be sure select correct versions of docs and beware old posts/tutorials. Click the `tag` dropdown on github repo select `1.0.x` – aarosil Jan 12 '16 at 04:39
  • `react-router` has the ability to [push a path](https://github.com/rackt/react-router/blob/master/docs/API.md#pushpathnameorloc) using `this.context.router.push( '/login' )`. Is that what you're looking for? Also your `ReferenceError` is because you didn't import `PropTypes` from anywhere. You need to use [`React.PropTypes`](https://facebook.github.io/react/docs/reusable-components.html) instead. – Josh David Miller Jan 12 '16 at 04:39
  • @JoshDavidMiller be aware linking to the `master` docs, it will change as it reference `master` not any specific version, see comment above about github `tag` – aarosil Jan 12 '16 at 04:45
  • @aarosil Yes, understood, but comments are intended to be short-lived, according to SO. That's why you cannot edit them after 5 minutes. I would take more care with a link in an *answer*. That said, for clarity, here's a [permalink to the `push` docs](https://github.com/rackt/react-router/blob/v2.0.0-rc4/docs/API.md#pushpathnameorloc). :-) – Josh David Miller Jan 12 '16 at 04:50
  • 1
    @JoshDavidMiller good point however I will not be suprised `react-router` api change within 5 min.. haha kidding, but just partially – aarosil Jan 12 '16 at 04:56

10 Answers10

293

1) react-router > V6 useNavigate hook:

If you have React >= 16.8 and functional components you can use the useNavigate hook from react-router.

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

const YourComponent = () => {
    const navigate = useNavigate();

    const handleClick = () => {
        navigate("/path/to/push");
    }

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

export default YourComponent;

2) react-router > V5 useHistory hook:

If you have react-router v5 and functional components you can use the useHistory hook from react-router.

import React from 'react';
import { useHistory } from 'react-router-dom';

const YourComponent = () => {
    const history = useHistory();

    const handleClick = () => {
        history.push("/path/to/push");
    }

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

export default YourComponent;

3) react-router > V4 withRouter HOC:

As @ambar mentioned in the comments, React-router has changed its codebase since its V4. Here is the documentation for withRouter

import React, { Component } from 'react';
import { withRouter } from "react-router-dom";

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

export default withRouter(YourComponent);

4) React-router < V4 with browserHistory

You can achieve this functionality using react-router BrowserHistory. Code below:

import React, { Component } from 'react';
import { browserHistory } from 'react-router-dom';

export default class YourComponent extends Component {
    handleClick = () => {
        browserHistory.push('/login');
    };

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

5) Redux connected-react-router

If you have connected your component with redux, and have configured connected-react-router all you have to do is this.props.history.push("/new/url"); ie, you don't need withRouter HOC to inject history to the component props.

// reducers.js
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';

export default (history) => combineReducers({
    router: connectRouter(history),
    ... // rest of your reducers
});


// configureStore.js
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers';
...
export const history = createBrowserHistory();

export default function configureStore(preloadedState) {
    const store = createStore(
        createRootReducer(history), // root reducer with router state
        preloadedState,
        compose(
            applyMiddleware(
                routerMiddleware(history), // for dispatching history actions
                // ... other middlewares ...
            ),
        ),
    );

    return store;
}


// set up other redux requirements like for eg. in index.js
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router';
import configureStore, { history } from './configureStore';
...
const store = configureStore(/* provide initial state if any */)

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <> { /* your usual react-router v4/v5 routing */ }
                <Switch>
                    <Route exact path="/yourPath" component={YourComponent} />
                </Switch>
            </>
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);


// YourComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
...

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
          <div>
            <button onClick={this.handleClick} type="button">
          </div>
        );
      }
    };

}

export default connect(mapStateToProps = {}, mapDispatchToProps = {})(YourComponent);
Noushad
  • 6,063
  • 3
  • 25
  • 28
49

For the simple answer, you can use Link component from react-router, instead of button. There is ways to change the route in JS, but seems you don't need that here.

<span className="input-group-btn">
  <Link to="/login">Click to login</Link>
</span>

To do it programmatically in 1.0.x, you do like this, inside your clickHandler function:

this.history.pushState(null, 'login');

Taken from upgrade doc here

You should have this.history placed on your route handler component by react-router. If it child component beneath that mentioned in routes definition, you may need pass that down further

Reacting
  • 5,543
  • 7
  • 35
  • 86
aarosil
  • 4,848
  • 3
  • 27
  • 41
  • 3
    this is cool solution, but the reason why I am not using it, is because I need to do like a kind of validation first, so I need to put this in a function, like: ```if (true) { // redirect to login}``` so that is why I put that in an onClick function – Reacting Jan 12 '16 at 04:45
  • 5
    You can also do that in JSX: `{validation && Click to login}`. If validation false, nothing would render. – aarosil Jan 12 '16 at 04:46
  • I know what you mean, but I need the button to be there, if the validation is true, then redirect, otherwise an error messages should come up. – Reacting Jan 12 '16 at 04:51
  • @TheUnnamed I updated answer to show how do it in JS – aarosil Jan 12 '16 at 04:53
  • 1
    >Uncaught TypeError: Cannot read property 'pushState' of undefined – Reacting Jan 12 '16 at 04:56
  • @TheUnnamed which component you using that in, `history` will only be placed on components mentioned in the `Route` component, otherwise you need pass it down further – aarosil Jan 12 '16 at 05:00
  • yes, the component where I am using it, is a component mentioned in the Route component – Reacting Jan 12 '16 at 05:02
  • Just got it: `this.props.history.pushState(null, 'login');` – Reacting Jan 12 '16 at 05:06
  • 1
    Is it just me or is there a typo in this code? a self enclosing link tag – Aimal Khan Oct 17 '18 at 19:48
32

How to do a redirect to another route with react-router?

For example, when a user clicks a link <Link to="/" />Click to route</Link> react-router will look for / and you can use Redirect to and send the user somewhere else like the login route.

From the docs for ReactRouterTraining:

Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

to: string, The URL to redirect to.

<Redirect to="/somewhere/else"/>

to: object, A location to redirect to.

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
jtlindsey
  • 4,346
  • 4
  • 45
  • 73
  • The provided solution throws an error ` elements are for router configuration only and should not be rendered`. – t1gor Mar 27 '18 at 09:52
  • 1
    It gets worse: ` "export 'Redirect' was not found in 'react-router' ` What is going on with these Router packages? I need to check and compare every version in every application and use different methods for each version? Train-wreck react. – Rin and Len May 26 '23 at 09:55
21

Easiest solution for web!

Up to date 2020
confirmed working with:

"react-router-dom": "^5.1.2"
"react": "^16.10.2"

Use the useHistory() hook!

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


export function HomeSection() {
  const history = useHistory();
  const goLogin = () => history.push('login');

  return (
    <Grid>
      <Row className="text-center">          
        <Col md={12} xs={12}>
          <div className="input-group">
            <span className="input-group-btn">
              <button onClick={goLogin} type="button" />
            </span>
          </div>
        </Col>
      </Row>
    </Grid>
  );
}
Scott Plunkett
  • 211
  • 2
  • 4
16

I know this is an old question, but for whoever comes here in 2021 and after as of React Router V6 useHistory is no longer exported from react-router-dom and you have to import useNavigate instead. Sample code is below:

import { useNavigate } from "react-router-dom"

and inside your react class or functional component:

const navigate = useNavigate()
navigate("/404")
U.Y.
  • 749
  • 10
  • 16
10

With react-router v2.8.1 (probably other 2.x.x versions as well, but I haven't tested it) you can use this implementation to do a Router redirect.

import { Router } from 'react-router';

export default class Foo extends Component {

  static get contextTypes() {
    return {
      router: React.PropTypes.object.isRequired,
    };
  }

  handleClick() {
    this.context.router.push('/some-path');
  }
}
Tom Van Rompaey
  • 3,556
  • 20
  • 22
9

The simplest solution is:

import { Redirect } from 'react-router';

<Redirect to='/componentURL' />
Jackkobec
  • 5,889
  • 34
  • 34
2

Simplest Method without the use of any routing library

window.location.replace("/login")
Inder Pal Singh
  • 380
  • 4
  • 16
1

Update for react-router-dom version >= 6

useHistory has been replaced by useNavigate.

You can use useNavigate as follows:

import {useNavigate} from 'react-router-dom';
const navigate = useNavigate();
navigate('/login');
parth_07
  • 1,322
  • 16
  • 22
0

React-Router Solution

Why This Solution: Components load faster and routes (e.g. www.website.com/**signup**) and the components linked to them are easily managed in one location

How: You set up routes e.g. www.website.com/**home** to your components in index.js. Then you basically use hyperlinks in other components to go to those routes.

Step 1: Install react-router-dom.


npm install react-router-dom

Step 2: Create a Start and SignUp Component in ./src.


Start.jsx

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

class Start extends React.Component {
    constructor(props) {
        super(props);
    }

    render () {
        return (
            <div>
               <h1>Hello World!</h1>
               <Link to='signUp'>Sign Up</Link>
           </div>
        );
    }
};

export default Start

SignUp.jsx

import React from "react";

class SignUp extends React.Component {
    constructor(props) {
        super(props);
    }
    
    render() {
        return (
        <div>
            <h1>Sign Up</h1>
            <p>Sign up page</p>
        </div>
        );
    }
    }

export default SignUp;

Step 3: update your index.js and App.js with this code.


index.js

//Imports
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider} from 'react-router-dom';

import SignUp from './SignUp';
import Start from './Start';

/*This is where you create the routes - path is the 
route and element is the component that will be found there. */

const router = createBrowserRouter([
  {
      path: '/',
      element: <Start />
  },
  {
      path: 'signUp',
      element: <SignUp />
  }
]);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
        <RouterProvider router = { router } />
  </React.StrictMode>
);

App.js

import React from "react";
import Start from "./Start";

function App() {
  return (
    <div>
      <Start />
    </div>
  );
}

export default App;

Done. No more function component only navigation only instant client-sided routing and easy route management.

Hao
  • 159
  • 1
  • 4