0
votes

I have a react project that is using redux-thunk. I created an action that will hit an endpoint, then set store to data received. Currently, I am using .then but when I call the action in the componentdidmount, the data is not there. The component renders before the data is available. To fix this, I decided to turn my action into an async action and then await in my componentdidmount. The problem is, as soon as I put async in my action, I get this error....

Unhandled Rejection (Error): Actions must be plain objects. Use custom middleware for async actions.

Here is my code

Action

export const getCasesSuccess = async (data) => {
    return {
        type: GET_ALL_CASES,
        data
    }
};

export const getAllCases = () => {
    return (dispatch) => {
        axios.get('https://corona.lmao.ninja/all')
        .then(res => {
            const cases = res.data
            dispatch(getCasesSuccess(cases))
        })
        .catch(error => {
            throw(error)
        })
    }
}

Component where action is called

import React from "react";
import { connect } from "react-redux";
import { getAllCases } from "../../store/actions/index";
import AllCases from '../../components/allcases/allCases';

class DataContainer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {  }
    }

    componentDidMount = async () => {        
        await this.props.getAllCases() 
    }


    render() { 
        return ( 
            <div>
                <AllCases allCases={this.props.allCases} />
            </div>
         );
    }
}

const mapStateToProps = (state) => (
    {
      allCases: state.allCases
    }
  )

const mapDispatchToProps = dispatch => {
  return {
    getAllCases: () => dispatch(getAllCases()),
  }
}


export default connect(mapStateToProps, mapDispatchToProps)(DataContainer);
2

2 Answers

0
votes

Remove the async from componentDidmount and use the async and await in getAllCases method

export const getAllCases = async () => {
    return (dispatch) => {
        await axios.get('https://corona.lmao.ninja/all')
        .then(res => {
            const cases = res.data
            dispatch(getCasesSuccess(cases))
        })
        .catch(error => {
            throw(error)
        })
    }
}
0
votes

As the error messages says, Redux actions must be plain objects. Since you're using thunk middleware, you can dispatch functions. But you're returning a promise. Since the data loading is asynchronous, your component should check if the data exists and if it doesn't, render a loading indicator or something. In your reducer, you can set a default state for allCases to null which the DataContainer component will use when the component mounts.

export const getCasesSuccess = (data) => {
    return {
        type: GET_ALL_CASES,
        data
    }
};
import React from "react";
import { connect } from "react-redux";
import { getAllCases } from "../../store/actions/index";
import AllCases from '../../components/allcases/allCases';

class DataContainer extends React.Component {
    componentDidMount() {        
        this.props.getAllCases() 
    }


    render() {
        const { allCases } = this.props
        if (!allCases) {
          return <div>Loading...</div>
        }
    
        return ( 
            <div>
                <AllCases allCases={this.props.allCases} />
            </div>
         );
    }
}

const mapStateToProps = (state) => ({
  allCases: state.allCases
})

const mapDispatchToProps = {
  getAllCases,
}


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