Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

this.props.history.push works in some components and not others

I am trying to programmatically change pages using browserHistory.push. In one of my components, but not in a component that I embedded inside of that one.

Does anyone know why my project is throwing the error below only for the child component but not for the parent component?

Cannot read property 'push' of undefined

Parent Component

import React, {Component} from 'react'; import { browserHistory } from 'react-router'; import ChildView from './ChildView';  class ParentView extends Component {  constructor(props) {     super(props);     this.addEvent = this.addEvent.bind(this);   }  changePage() {     this.props.history.push("/someNewPage");   }  render() {     return (       <div>         <div>           <button onClick={this.changePage}>Go to a New Page!</button>         </div>          <ChildView />  // this is the child component where this.props.history.push doesn't work         </div>     );   } }  function mapStateToProps(state) {     return {         user: state.user     }; }  function matchDispatchToProps(dispatch) {     return bindActionCreators({       setName: setName     }, dispatch) }  export default connect(mapStateToProps, matchDispatchToProps)(ParentView); 

Child Component

    import React, {Component} from 'react';     import { browserHistory } from 'react-router';      class ChildView extends Component {      constructor(props) {         super(props);         this.addEvent = this.addEvent.bind(this);       }      changePage() {         this.props.history.push("/someNewPage");       }      render() {         return (           <div>             <div>               <button onClick={this.changePage}>Go to a New Page!</button>             </div>            </div>         );       }     }      function mapStateToProps(state) {         return {             user: state.user         };     }      function matchDispatchToProps(dispatch) {         return bindActionCreators({           setName: setName         }, dispatch)     }      export default connect(mapStateToProps, matchDispatchToProps)(ChildView); 

Router

// Libraries import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import { browserHistory } from 'react-router';  // Components import NotFound from './components/NotFound'; import ParentView from './components/ParentView'; import ChildView from './components/ChildView'; import SomeNewPage from './components/SomeNewPage';  // Redux import { Provider } from 'react-redux'; import {createStore} from 'redux'; import allReducers from './reducers';  const store = createStore(   allReducers,   window.devToolsExtension && window.devToolsExtension() );  const routes = (     <Router history={browserHistory}>       <div>         <Provider store={store}>             <Switch>               <Route path="/" exact component={Home} />               <Route path="/parentView" component={ParentView} />               <Route path="/someNewPage" component={SomeNewPage} />               <Route path="/childView" component={ChildView} />               <Route component={NotFound} />             </Switch>         </Provider>       </div>     </Router> );  export default routes; 

As you can see, the components are virtually exactly the same except that the child one is inside the parent one.

Note I have tried these approaches but they do not resolve the issue for me:

  • Uncaught TypeError: Cannot read property 'push' of undefined with correct import being available
  • React browserHistory.push giving Uncaught TypeError: Cannot read property 'push' of undefined
  • redirect to a page programmatically in react-router 2
like image 851
Rbar Avatar asked May 07 '17 22:05

Rbar


People also ask

What is the use of this props history push?

history. push() is another approach where we make use of the history props React Router provides while rendering a component. In other words, this works when the component is being rendered by React Router, bypassing the component as a Component prop to a Route.

Can we use history push in class component?

Note: You can only use this. props. history. push() function inside the component page that already listed on your project route, or simply use the withRouter() HOC if the component is not available in the route list.

What is the purpose of push () and replace () methods of history?

replace and history. push? The difference is that, in case of push - a new record is added in the history, while for replace it deletes the last record and puts the new one.

What is a prop in a component and what is it used for?

“Props” is a special keyword in React, which stands for properties and is being used for passing data from one component to another. Furthermore, props data is read-only, which means that data coming from the parent should not be changed by child components.


Video Answer


2 Answers

Using withRouter is fine, an alternative option is to pass the history as a prop from parent to child (without using withRouter), e.g:

Parent

<SignupForm history={this.props.history}/> 

Child

this.props.history.push('/dashboard'); 
like image 40
Notorious Avatar answered Oct 05 '22 11:10

Notorious


You answered your question in your question.

As you can see, the components are virtually exactly the same except that the child one is inside the parent one.

The very fact that the component is nested one further is your issue. React router only injects the routing props to the component it routed to, but not to the components nested with in.

See the accepted answer to this question. The basic idea is that you now need to find a way to inject the routing props to the child component. You can do that by wrapping the child in a HOC withRouter.

export default withRouter(connect(mapStateToProps, matchDispatchToProps)(ChildView)); 

I hope this helps.

like image 61
Chaim Friedman Avatar answered Oct 05 '22 11:10

Chaim Friedman