Search code examples
reactjsreduxredux-thunk

Dispatching action on Redux during asynchronus API request using redux thunk


I am quite new to redux and react. I have also checked out a number of ways here to solve my problem but it appears I am not making any headway.

I intend performing an asynchronous operation using redux-thung following the tutorial https://github.com/reduxjs/redux-thunk, but the challenge I have is that the the function sendApplication() does not dispatch the action nextPage() neither does the function hitUrl() works. I have been on this issues for days. Someone should help me out please.

import React from 'react';
import { withStyles} from '@material-ui/styles';
import { FormLabel, TextField, Button } from '@material-ui/core';
import {connect} from 'react-redux';
import { nextPage, previousPage, enableBtnAvailability} from '../../actions/formPageController';
import { updateTextValueAvailability, clearField } from '../../actions/formInputController';
import { useStyles } from '../Styles/formStyles';
import { ValidatorForm, TextValidator} from 'react-material-ui-form-validator';
import sendApplication from '../../utility/sendRequest';
import { bindActionCreators } from 'redux';
const axios = require('axios');


const AvailablityTab=  withStyles({
  
})((props) => {
    console.log(props);
    
    const handleChange=(e)=>{
        const name= e.target.name;
        const value = e.target.value;
        const {updateTextValueAvailability} = props;
        updateTextValueAvailability(name,value);

        let unfilledFormFieldArray = props.text.filter((item)=> {
          console.log(item);
          return item.value=== "";
        })
        console.log(unfilledFormFieldArray);
        console.log(unfilledFormFieldArray.length);
        if(unfilledFormFieldArray.length ===0){
          const {enableBtnAvailability} = props;
          enableBtnAvailability();
         
        } 
        
    }

    const handleSubmit=()=>{
      //const {postApplication} = props;
      sendApplication();
      console.log(props);
     
      console.log('he submit');

    }


    const hitUrl = async function () {
      //alert('hi')
      try {
          console.log(3);
        const response = await axios.get('http://localhost:1337/api/v1/application/fetch-all');
        console.log(response);
        return response;
  
      } catch (error) {
        console.error(error);
      }
    };
  
  
  
   const sendApplication = () => {
      console.log(4);
      console.log(props);
      return function(props) {
        console.log('xyz');
        console.log(props);
        const {nextPage} = props; 
          // dispatch(nextPage());
          nextPage();
          console.log(5);
          alert('hi2')
        return hitUrl().then(
          () => {
              console.log('thunk success');
              nextPage();
          },
          () => {
              console.log('thunk error');
              //props.dispatch(previousPage())
          },
        );
      };
    }
  
    
    
    const handlePrevious=()=>{
      const {previousPage} = props;
      previousPage();
 }


    console.log(props);
    const classes = useStyles();
    let validationRule = ['required'];
    let errorMessages = ['This field is required'];
    return (
  <div className="formtab">
  <ValidatorForm //ref="form"
                onSubmit={handleSubmit}
                onError={errors => console.log(errors)}
            >
      {props.text.map((each)=>{
        let onFocus = false;
        if(each.id === 1){
          onFocus = true;
        }
          
          return(<div className={classes.question} key={each.id}>
        <FormLabel className={classes.questionLabel} component="legend">{each.label}</FormLabel>
        <TextValidator
                id={"filled-hidden-label"}
                className={classes.textField}
                hiddenLabel
                variant="outlined"
                fullWidth
                name={each.name}
                onChange={handleChange}
                value={each.value}
                margin= "none"
                placeholder={each.placeholder}
                validators={validationRule}
                    errorMessages={errorMessages}
                autoFocus= {onFocus}
            />
      </div>)
      })}

      
      <div className={classes.buttondiv} >
      <Button className={classes.prev} variant="contained" onClick={handlePrevious}>Previous</Button>
      <Button className={classes.next} variant="contained" type="submit" disabled={!props.btnActivator} >Submit</Button>
      </div>

    </ValidatorForm>  
  </div>  
 
    
)});


const mapStateToProps= (state)=>{
  const availablity = state.availabilityQuestion;
  return {
      text: availablity.text,
      radio: availablity.radio,
      btnActivator: state.btnActivator.availability
  }
}

const mapDispatchToProps = dispatch => bindActionCreators({
  postApplication: sendApplication,
  previousPage,
  enableBtnAvailability,
  updateTextValueAvailability,
  nextPage,
  clearField

}, dispatch)

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


Solution

  • Since sendApplication returns a function, but does not execute it, you can call it like this:

    sendApplication()(props); // it looks like you expect props to be passed to your function
    

    This should successfully execute your nextPage function and return the value returned by hitUrl.

    The alternative would be to execute the function instead of returning it

    sendApplication(props);
    ...
    const sendApplication = (props) => {
      console.log('xyz');
      console.log(props);
      const {nextPage} = props; 
      // dispatch(nextPage());
      nextPage();
      console.log(5);
      alert('hi2')
      return hitUrl().then(
        () => {
          console.log('thunk success');
          nextPage();
        },
        () => {
          console.log('thunk error');
          //props.dispatch(previousPage())
        },
      );
    };
    

    Now we've eliminated the internal function and just called it directly instead. Now calling sendApplication will return the return value of hitUrl.