4

I am working on a react - redux application. Now I faced an issue to dispatch the action. The following code cannot dispatch the generateReport action.

import React, { Component } from "react";
import { Button, Icon } from "semantic-ui-react";
import { connect } from "react-redux";
import { submit, getFormValues, isValid } from "redux-form";
import { generateReport } from "../actions/generateActions";
import { Link } from "react-router-dom";

const docsButtonStyle = {
  position: "fixed",
  marginBottom: "0.5em",
  marginLeft: "0.1em",
  bottom: 0,
  left: 0,
  animation: "back-to-docs 1.5s ease-in-out infinite",
  zIndex: 6
};

class ButtonGroup extends Component {
  generate = () => {
    this.props.generateReport(this.props.values);
  };     

  render() {
    return (
      <div style={docsButtonStyle}>
        <Button.Group vertical>              
          <Button animated="fade" color="teal" onClick={this.generate}>
            <Button.Content hidden>Generate</Button.Content>
            <Button.Content visible>
              <Icon name="chart bar" size="large" />
            </Button.Content>
          </Button>
        </Button.Group>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  values: getFormValues("privateForm")(state),
  valid: isValid("privateForm")(state)
});

const mapDispatchToProps = dispatch => ({
  generateReport,
  remoteSubmit: () => {
    dispatch(submit("privateForm"));
  }
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ButtonGroup);

generateActions.js

export const generateReport = values => async dispatch => {
  console.log("test");
  try {
    dispatch(generateReportBegin());
    const response = await axios.post(`${ROOT_URL}/submit`, values);
    dispatch(generateReportSuccess());
  } catch (error) {

  }
};

If I change connect function into

export default connect(
  mapStateToProps,
  {generateReport}
)(ButtonGroup);

It works. Can anyone tell me why it does not work in the first situation? Thanks.

PLee
  • 393
  • 9
  • 26

1 Answers1

1

This happens due to different behavior of connect function depending of passed arguments to mapDispatchToProps

  1. If you pass function it will be called with dispatch as first argument and resulting object will be merged to props. In this case it is assumed that in supplied function you prepare dispatch calls for every action.

    In code

    const mapDispatchToProps = dispatch => ({
        generateReport,
        remoteSubmit: () => {
            dispatch(submit("privateForm"));
        }
    });
    

    mapDispatchToProps will be called with dispatch as argument and produces object with 2 functions. remoteSubmit should work correctly as it is bound to dispatch. But generateReport is just some external function which is passed as is. So on any call to this.props.generateReport just function will be returned taking dispatch as argument. Redux belives that you already prepared everything needed for dispatching in mapDispatchToProps so it does nothing.

  2. If you pass object as mapDispatchToProps (what is you do in second example), connect will call bindActionCreators for you and wrap generateReport inside dispatch call. So it works.

To make both actions work you should wrap all action creators in dispatch calls.

Possible ways to do so

const mapDispatchToProps = dispatch => ({
    generateReport: bindActionCreators(generateReport, dispatch),
    remoteSubmit: () => {
        dispatch(submit("privateForm"));
    }
});

Another way

const mapDispatchToProps = dispatch => ({
    generateReport: (value) => dispatch(generateReport(value)),
    remoteSubmit: () => {
        dispatch(submit("privateForm"));
    }
});

Or call mapDispatchToProps with one object containing all action creators. In this case connect will call bindActionCreators for you.

const mapDispatchToProps = {
    generateReport,
    remoteSubmit: () => submit("privateForm")
    }
Fyodor Yemelyanenko
  • 11,264
  • 1
  • 30
  • 38