React-router v4 this.props.history.push(...) not working

199,177

Solution 1

So I came to this question hoping for an answer but to no avail. I have used

const { history } = this.props;
history.push("/thePath")

In the same project and it worked as expected. Upon further experimentation and some comparing and contrasting, I realized that this code will not run if it is called within the nested component. Therefore only the rendered page component can call this function for it to work properly.

Find Working Sandbox here

  • history: v4.7.2
  • react: v16.0.0
  • react-dom: v16.0.0
  • react-router-dom: v4.2.2

Solution 2

It seems things have changed around a bit in the latest version of react router. You can now access history via the context. this.context.history.push('/path')

Also see the replies to the this github issue: https://github.com/ReactTraining/react-router/issues/4059

Solution 3

For me (react-router v4, react v16) the problem was that I had the navigation component all right:

import { Link, withRouter } from 'react-router-dom'

class MainMenu extends Component {

  render() {
    return (
            ...
            <NavLink to="/contact">Contact</NavLink>
            ...
    );
  }
}

export default withRouter(MainMenu);

Both using either

to="/contact" 

or

OnClick={() => this.props.history.push('/contact')}; 

The behavior was still the same - the URL in browser changed but wrong components were rendered, the router was called with the same old URL.

The culprit was in the router definition. I had to move the MainMenu component as a child of the Router component!

// wrong placement of the component that calls the router
<MainMenu history={this.props.history} />
<Router>
   <div>
     // this is the right place for the component!
     <MainMenu history={this.props.history} />
     <Route path="/" exact component={MainPage} />
     <Route path="/contact/" component={MainPage} />
   </div>
</Router>

Solution 4

You can try to load the child component with history. to do so, pass 'history' through props. Something like that:

  return (
  <div>
    <Login history={this.props.history} />
    <br/>
    <Register/>
  </div>
)

Solution 5

You can get access to the history object's properties and the closest 's match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.

import React, { Component } from 'react'
import { withRouter } from 'react-router'; 
// you can also import "withRouter" from 'react-router-dom';

class Example extends Component {
    render() {
        const { match, location, history } = this.props
        return (
            <div>
                <div>You are now at {location.pathname}</div>
                <button onClick={() => history.push('/')}>{'Home'}</button>
            </div>
        )
    }
}


export default withRouter(Example)
Share:
199,177
Admin
Author by

Admin

Updated on December 31, 2021

Comments

  • Admin
    Admin over 2 years

    I'm trying to route programatically using this.props.history.push(..) but it doesn't seem to work.

    Here's the router:

    import {
     BrowserRouter as Router,
     Route
    } from 'react-router-dom';
    
    <Router>
     <Route path="/customers/" exact component={CustomersList} />
     <Route path="/customers/:id" exact component="{Customer} />
    </Router>
    

    In CustomerList, a list of customers is rendered. Clicking on a customer (li) should make the application route to Customer:

    import { withRouter } from 'react-router'
    
    class Customers extends Component {
      static propTypes = {
        history: PropTypes.object.isRequired
      }
    
     handleCustomerClick(customer) {
       this.props.history.push(`/customers/${customer.id}`);
     }
    
     render() {
       return(
        <ul>
          { this.props.customers.map((c) =>
            <li onClick={() => this.handleCustomerClick(c)} key={c.id}>
              {c.name}
            </li> 
        </ul>
      )
    
     }
    }
    
    //connect to redux to get customers
    
    CustomersList = withRouter(CustomersList);
    export default CustomersList;
    

    The code is partial but illustrates perfectly the situation. What happens is that the browser's address bar changes accordingly to history.push(..), but the view does not update, Customer component is not rendered and CustomersList is still there. Any ideas?

  • cgat
    cgat over 6 years
    A better way to do this is to use withRouter HOC. github.com/ReactTraining/react-router/blob/master/packages/…
  • Adam Barnes
    Adam Barnes about 6 years
    Given how fast react-router, (and for that matter, the whole JS ecosystem moves), it will improve your answer if you include what version you're on, and your answer will be amazing if you provide an MCVE. Services like JSFiddle should help with that.
  • anothernode
    anothernode almost 6 years
    Welcome to Stack Overflow! It would be great if you could add a little bit of an explanation about why you think this call solves the problem asked about in the question.
  • Hashan Seneviratne
    Hashan Seneviratne almost 6 years
    this.handleCustomerClick = this.handleCustomerClick.bind(this) did the trick for me.
  • SuperUberDuper
    SuperUberDuper about 5 years
    I get history.push( is not a function
  • Subdigger
    Subdigger over 3 years
    IMHO this is the same as this.pros.history.pus(). You just put it into other variable. both undefined to me....
  • Subdigger
    Subdigger over 3 years
    looks like this is the way... and it is very sad