Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Action creator is called but action is not dispatched

I have a component that successfully uses redux-form onSubmit to call an action creator. The creator performs an ajax call but the the action is never dispatched to save it to the store. I must have something messed up in the wiring of react-redux and redux-form, possibly in the binding of the action creator. I have read everything that I have found on Google and still can't find the problem. Any ideas? ( I have included redux-promise to handle the request promise, but it never makes it that far )

import React from 'react';
import { Field, reduxForm } from 'redux-form';
import validate from '../utils/add_person_validation';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { addPersonResponseAction } from '../actions/index';
import renderField from '../components/render_input_field';

// call the action creator - this part succeeds 
const doSubmit = function(values) {
  addPersonResponseAction(values);
};


let AddPersonContainer = (props) => {
  const {
    handleSubmit,
    pristine,
    reset,
    submitting
  } = props;


  return (
    <div className="row">
      <form onSubmit={handleSubmit(doSubmit)} >
          <div className="col-sm-6">
              <fieldset>
                <legend>Person Info</legend>
                <div className="form-group">
                  <Field name="personFirstName" component={renderField} type="text" label="First Name" className="form-control" />
                  <Field name="personLastName" component={renderField} type="text" label="Last Name" className="form-control" />
                  <Field name="birthday" component={renderField} type="date" label="Birthday" className="form-control" />
                  <Field name="group" component={renderField} type="text" label="Group" className="form-control" />
                </div>
              </fieldset>
          </div>
          <div className="form-buttons-container">
            <button className="btn btn-default form-button" type="submit" disabled={pristine || submitting}>Submit</button>
            <button className="btn btn-default form-button" type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
          </div>
      </form>
    </div> 
  );
};


const mapStateToProps = function({ addPersonResponse }) {
  return { addPersonResponse };
};

const mapDispatchToProps = function(dispatch) {
  return bindActionCreators( {addPersonResponseAction}, dispatch);
};

const form = reduxForm({ form: 'addPerson', validate: validate });

AddPersonContainer = connect(mapStateToProps, mapDispatchToProps)(form(AddPersonContainer));

export default AddPersonContainer;

/********************************************
* Action creator
**********************************************/

import axios from 'axios';

export const ADD_PERSON_RESPONSE = 'ADD_PERSON_RESPONSE';

export const addPersonResponseAction = (data) => {

  const postURL = 'http://some-url/addperson';
  const request = axios.post(postURL, { data });

  return {
    type: ADD_PERSON_RESPONSE,
    payload: request
  };

};
like image 246
brandonlehr Avatar asked Sep 27 '16 23:09

brandonlehr


1 Answers

Redux wraps actions using mapDispatchToProps - but you are calling the unwrapped version by using the imported method.

// call the action creator - this part succeeds 
const doSubmit = function(values) {
  addPersonResponseAction(values);    <------ Redux does not know anything about this
};

Try:

let AddPersonContainer = (props) => {
  const {
    handleSubmit,
    pristine,
    reset,
    submitting
  } = props;

  const doSubmit = function(values) {
    props.addPersonResponseAction(values);  <----- Try this
  }

  return (
    <div className="row">
      <form onSubmit={handleSubmit(doSubmit)} >
          <div className="col-sm-6">
              <fieldset>
                <legend>Person Info</legend>
                <div className="form-group">
                  <Field name="personFirstName" component={renderField} type="text" label="First Name" className="form-control" />
                  <Field name="personLastName" component={renderField} type="text" label="Last Name" className="form-control" />
                  <Field name="birthday" component={renderField} type="date" label="Birthday" className="form-control" />
                  <Field name="group" component={renderField} type="text" label="Group" className="form-control" />
                </div>
              </fieldset>
          </div>
          <div className="form-buttons-container">
            <button className="btn btn-default form-button" type="submit" disabled={pristine || submitting}>Submit</button>
            <button className="btn btn-default form-button" type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
          </div>
      </form>
    </div> 
  );
};

Because the function you are defining does not have access to props this gives a bit of a twist, so try refactoring it into the component definition.

This is a source of confusion because it is required to import the function so mapDispatchToProps can wrap it...but there is temptation to forget that the real action is in props, not the function itself. So I'm sure you are seeing results in the actual action function, but redux does not know because it is not wrapped in dispatch.

like image 94
erik-sn Avatar answered Oct 12 '22 13:10

erik-sn