Search code examples
reactjsreact-redux-form

Uncaught TypeError: this.props.dispatch is not a function


I am trying to dispatch an action when I submit a form but I'm getting this:

Uncaught TypeError: this.props.dispatch is not a function

This is my class:

/**
 *
 * CatalogPage
 *
 */

import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';
import { Form, Control } from 'react-redux-form/immutable';

import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import makeSelectCatalogPage from './selectors';
import reducer from './reducer';
import saga from './saga';

export class CatalogPage extends React.Component { // eslint-disable-line react/prefer-stateless-function

  handleSubmit = (user) => {
    this.props.dispatch({ type: 'test action' });
  }

  render() {
    return (
      <Form
        model="user"
        onSubmit={(user) => this.handleSubmit(user)}
      >
        <label htmlFor=".firstName">First name:</label>
        <Control.text model=".firstName" id=".firstName"/>

        <label htmlFor=".lastName">Last name:</label>
        <Control.text model=".lastName" id=".lastName"/>

        <button type="submit">
          Finish registration!
        </button>
      </Form>
    );
  }
}

CatalogPage.propTypes = {};

const mapStateToProps = createStructuredSelector({
  catalogpage: makeSelectCatalogPage(),
});

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
  };
}

const withConnect = connect(mapStateToProps, mapDispatchToProps);

const withReducer = injectReducer({ key: 'catalogPage', reducer });
const withSaga = injectSaga({ key: 'catalogPage', saga });

export default compose(
  withReducer,
  withSaga,
  withConnect,
)(CatalogPage);

I thought that the compose function at the bottom would connect my component to the store and thus have access to the dispatch function through this.props.dispatch. But it's not working, what am I missing?

Thanks!

EDIT: I've changed handleSubmit to arrow function but problem still persists

handleSubmit = (user) => {
    this.props.dispatch({ type: 'test action' });
  }

EDIT: The problem resolved itself

Something to mention is that react-boiler-plate is not as user-friendly as one might expect. There's alot of weird things that are happening and took me a long time to debug.


Solution

  • The problem here is the misunderstanding of a class method and the way that React manages instances.

    You can do three things to avoid this problem:

    1) Convert the (handleSubmit) function to an arrow function so in that case, it won't have its own this.

    handleSubmit = (user) => { // ...logic here }
    

    2) Create a constructor inside the component and do the next step:

    this.handleSubmit = this.handleSubmit.bind(this)
    

    In this case, you attach this to the function each time an instance is created.

    3) When you call the method inside the render use the .bind() to bind this:

    onSubmit={(user) => this.handleSubmit.bind(this, user)}