skip to Main Content

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.

3

Answers


  1. From what I can tell it appears that fetchData is an asynchronous action creator, e.g. a Thunk action, and as such it needs to be dispatched to the store. In the code you’ve shared you are only calling the first function, and never the returned function that returns a Promise object to chain from.

    It’s also generally considered anti-pattern to mix async/await with Promise chains. Use one or the other.

    The useEffect hook callback function also cannot be an async funcion, it must be a regular synchronous function.

    const fetchData = (name) => async (dispatch) => {
      dispatch(fetchDataRequest());
    
      try {
        const { data } = await axios.get(url);
        return data;
      } catch(error) {
        return [];
      };
    };
    
    import { useDispatch } from "react-redux";
    import { fetchData } from "../../Actions/userActions";
    
    export const ParentModal = forwardRef((props, ref) => {
      const dispatch = useDispatch();
    
      ...
    
      useEffect(() => {
        dispatch(fetchData("foo"))
          .then((res) => {
            console.log({ res });
          });
      }, [dispatch]);
    
      ...
    
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
  3. First of all, modify your fetchData as i see either an incomplete code or some syntax error.

    Modify fetchData function

    // i'll maintain same syntax for easy understanding 
    const fetchData = (name) => {
      return async(dispatch) => {
        dispatch(fetchDataRequest());
    
        try {
          const response = await axios.get(url);
          const data = response.data;
          return data; // return the data from your api if any, to be used when this function is called
        } catch (error) {
          console.error(error);
          return [];
        }
      };
    };
    1. call the function and check if there’s any return data
    import {
      fetchData
    } from "../../Actions/userActions";
    
    export const ParentModal = hooks.forwardRef((props, ref) => {
      const [initialLoading, setInitialLoading] = hooks.useState(true);
    
      hooks.useEffect(() => {
        fetchData("foo")
          .then((res) => {
            console.log("result arrived!!!");
            console.log({
              res
            }); // this should print the response into your console just so you see what returned from the function 
            setInitialLoading(false); // Set loading to false when data arrives
          })
          .catch((error) => {
            console.error(error);
            setInitialLoading(false); // Handle errors and set loading to false
          });
      }, []);
    
      return initialLoading ? ( <
        mui.CircularProgress className = "smloader" / >
      ) : (
        ReactDOM.createPortal( <
          div >
          <
          ChildModal open = {
            open
          }
          /> <
          /div>,
          // ...
        )
      );
    });
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search