Search code examples
javascriptreactjsreduxredux-thunk

How to call async function from within another component in reac js redux web application?


I have the code below but it gives error:

const fetchData = (name) => {
  return async (dispatch) => {
    dispatch(fetchDataRequest());
        
    await axios
      .get(url)
      .then((response) => {
        data = response;
      })
      .catch((error) => {
        data = [];
      });
    return data;
  };
};

Component code:

import {fetchData} from "../../Actions/userActions"
import {useEffect, useState, forwardRef} from "react";

export const ParentModal = forwardRef((props, ref) => {
  console.log(" type:" + typeof fetchData );
    
  const [initialLoading, setinitialLoading] useState(true);

  useEffect (async () => {
    fetchData("foo").then(async (res) => {
      console.log("result arrived!!!");
    });
  }, []);
    
  return (initialLoading) ? (
    <mui.CircularProgress className="smloader" />
    ReactDOM.createPortal (
    <div>
    <ChildModal
    open={open}
    />
    ....

But it gives this error:

Uncaught (in promise) TypeError: (0, _Serviceworkers_redux_Actions_userActions__WEBPACK_IMPORTED_MODULE_4__fetchData(...).then is not a function

fetchData is a call to remote API. What I want to accomplish is that I want to render ChildModal only after data from remote API has arrived in ParentModal.

Note that console prints: type: function

but result arrived!!! never printed.

Actions are thunk actions and reducers. Most code is removed as actual code is much bigger. Just cut down to minimum to solve the problem.


Solution

  • fetchData function returns a thunk (a function that returns a function) instead of a promise. To call a thunk, you need to call it with dispatch

    import { fetchData } from '../../Actions/userActions';
    
    export const ParentModal = hooks.forwardRef((props, ref) => {
      const dispatch = useDispatch();
        
      const [initialLoading, setinitialLoading] = hooks.useState(true);
    
      hooks.useEffect(() => {
        dispatch(fetchData("foo")).then(() => {
          console.log("result arrived!!!");
          setinitialLoading(false);
        });
      }, [dispatch]);
        
      return (
        <React.Fragment>
          {initialLoading && <mui.CircularProgress className="smloader" />}
          {!initialLoading && ReactDOM.createPortal(
            <ChildModal open={open} />,
            document.getElementById('modal-root')
          )}
        </React.Fragment>
      );
    });
    

    ps. set the initialLoading flag to false in the .then() callback in order for the ChildModal to be rendered after the data has arrived

    official Redux documentation: https://redux.js.org/advanced/async-actions#async-action-creators