1

I have looked over the other questions and none of the answers seem to help. I do not have redux-form installed. I am brand new to react (and pretty new to dev as well)

In my App.js I am importing:

import React, { Component } from 'react';
import {
  BrowserRouter as Router, 
  Route, 
  Switch,
  NavLink
} from 'react-router-dom'

class App extends Component {
  render() {
    return (
      <Router>
        <div className="App">
          <nav className="uk-navbar fixed">
            ...
          </nav>  
          <Switch>
            <Route exact path = "/" component={Home}/>
            <Route path = "/tasks/new" component={AddTask}/>
            ... more routes
            </Route>
          </Switch>
        </div>
      </Router>
    );
  }
}

export default App;

All my forms (total of 3) have a handleOnSubmit, which I have as an arrow function:

  handleOnSubmit = (event) => {
    event.preventDefault()
    apiRequest.post(`projects/`, this.state)
    this.props.router.push('/client');
  }

Being call from the form:

<form className="uk-form" onSubmit={this.handleOnSubmit}>

And, I do not have this.props inside my handleOnSubmit, so I cannot reroute the user.

Here is the full error:

TypeError: Cannot read property 'push' of undefined
AddProject._this.handleOnSubmit
src/components/projects/AddProject.js:20
  17 | handleOnSubmit = (event) => {
  18 |   event.preventDefault()
  19 |   apiRequest.post(`projects/`, this.state)
> 20 |   this.props.router.push('/client');
  21 | }
  22 | 
  23 | handleOnChange = event => {
View compiled
▼ 14 stack frames were expanded.
Object../node_modules/react-dom/lib/ReactErrorUtils.js.ReactErrorUtils.invokeGuardedCallback
node_modules/react-dom/lib/ReactErrorUtils.js:69
executeDispatch
node_modules/react-dom/lib/EventPluginUtils.js:85
Object.executeDispatchesInOrder
node_modules/react-dom/lib/EventPluginUtils.js:108
executeDispatchesAndRelease
node_modules/react-dom/lib/EventPluginHub.js:43
executeDispatchesAndReleaseTopLevel
node_modules/react-dom/lib/EventPluginHub.js:54
forEachAccumulated
node_modules/react-dom/lib/forEachAccumulated.js:24
Object.processEventQueue
node_modules/react-dom/lib/EventPluginHub.js:254
runEventQueueInBatch
node_modules/react-dom/lib/ReactEventEmitterMixin.js:17
Object.handleTopLevel [as _handleTopLevel]
node_modules/react-dom/lib/ReactEventEmitterMixin.js:27
handleTopLevelImpl
node_modules/react-dom/lib/ReactEventListener.js:72
ReactDefaultBatchingStrategyTransaction.perform
node_modules/react-dom/lib/Transaction.js:143
Object.batchedUpdates
node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62
Object.batchedUpdates
node_modules/react-dom/lib/ReactUpdates.js:97
dispatchEvent
node_modules/react-dom/lib/ReactEventListener.js:147
▲ 14 stack frames were expanded.

Any help is greatly appreciated. Thanks so much!

I have super(), and both this.props.router.push and this.props.router.history don't work.

this.props doesn't work at all in the function.

Here is my whole component -- thanks so much again!

import React, { Component } from 'react'

import apiRequest from '../../redux/modules/apiRequests'

export default class AddProject extends Component {

  constructor(props){
    super(props)
    this.state = {
      name: '',
      bill_rate: '',
      clientId: this.props.clientId
    }
  }
  
  handleOnSubmit = (event) => {
    event.preventDefault()
    apiRequest.post(`projects/`, this.state)
    this.props.router.push('/client');
  }

  handleOnChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    });
  }
 
  render() {
    return (
      <div>
        <form className="uk-form" onSubmit={this.handleOnSubmit}>
          <fieldset>
              <legend>Add Project</legend>
              <div className="uk-form-row">
                <legend>Project Name</legend>
                <input
                type="text"
                placeholder="Project Name"
                name="name"
                onChange={this.handleOnChange} />
              </div>
              <div className="uk-form-row">
                <legend>Project Bill Rate</legend>
                <input
                type="text"
                placeholder="Project Bill Rate"
                name="bill_rate"
                onChange={this.handleOnChange} />
              </div>
              <input
                type="hidden"
                name={this.props.clientID}
                />
              <input
            type="submit"
            value="Add Project" />
          </fieldset>
        </form>
      </div>
    );
  }
};
madav
  • 2,918
  • 1
  • 13
  • 17
  • 2
    Possible duplicate of [Programmatically navigate using react router](https://stackoverflow.com/questions/31079081/programmatically-navigate-using-react-router) – Marko Gresak Jul 31 '17 at 00:37
  • 1
  • No need to bind with this syntax: `Handler = (event) => { }` – btzr Jul 31 '17 at 04:09
  • This syntax ensures `this` is bound within handleClick ^^ – btzr Jul 31 '17 at 04:12
  • https://facebook.github.io/react/docs/handling-events.html – btzr Jul 31 '17 at 04:13
  • Possible duplicate of [ReactJs this.props.router undefined](https://stackoverflow.com/questions/37077351/reactjs-this-props-router-undefined) – btzr Jul 31 '17 at 04:35
  • can you post the code of the component where your handleOnSubmit handler and form is defined – Umesh Jul 31 '17 at 10:46
  • I posted the component. Thanks. I also tried doing onSubmit=() => {this.handleOnSubmit.(this) but it only gave me the data from the form, the this.props.router was still unavailable. – madav Jul 31 '17 at 12:15
  • Considering you are using the latest version of React Router (>4.x.x) your first imports are wrong. Switch and Route should be imported from package `react-router`: `import { Switch, Route } from 'react-router';` – Dez Jul 31 '17 at 17:49

3 Answers3

3

This is not a direct answer to your error but React Router v4 has a declarative alternative:

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

// in render function
this.state.shouldRedirect ? <Redirect to="redirect-url"/> : null

// in method or somewhere else (lifecycle hooks etc)
this.setState({shouldRedirect: true});

As soon as Redirect is rendered, you'll get redirected.

Solo
  • 6,687
  • 7
  • 35
  • 67
  • This worked great!!! One note, it will not redirect to the same page (after form submit). But I'll update the page with the new form data through dispatching an action. Thanks sooo much! I upvoted you but since I'm a newbie it won't show :( – madav Aug 01 '17 at 23:55
2

I think you just need to replace this.props.router.push with this.props.history.push()

Anthony
  • 6,422
  • 2
  • 17
  • 34
0

You need to add constructor

constructor(props){
super(props);
}

Edit: Add this

App.contextTypes = {
  router: PropTypes.object,
};

Then instead of this.props.router.push() try

this.context.router.push()
  • hi, I have this in my constructor, see the last snippet. – madav Jul 31 '17 at 12:54
  • Thanks for this, I must be missing something, I put App.contextTypes inside the constructor below this.state and imported my App file and import PropTypes from 'prop-types', and this.context was null. – madav Aug 01 '17 at 23:44