Search code examples
reactjsredux

React Redux - Wait until data is loaded


I'm using Redux (+ thunk) to fetch data from my API. I implemented a Data Fetcher component that calls all the actions and once done, dispatches a LOADED. In my actual main component where I render content, I wait until isLoaded flag in the props is set to true.

Here's the method in the data fetcher:

const fetchData = () => {
    if (isAuthenticated) {
        const p = [];
        p.push(fetchDataSetOne());
        p.push(fetchDataSetTwo());
        Promise.all(p).then( () => setHasLoaded() );
    }
}

Each of those fetch methods returns an axios promise, in which I dispatch once retrieved like so:

export const fetchDataSetOne = () => dispatch => {
  return axios.get(`${API_URL}/dataSetOne`)
    .then(res => {
        dispatch({
            type: FETCH_ALL_DATA_SET_ONE,
            payload: res.data.docs
        });
    });
};

In my component's render function I only render the content when loaded (which is set by the LOADED dispatch from the setHasLoaded action) like so:

{ hasLoaded && <MyContent> }

Even though I "wait" for the actions to finish (= Promise.all), my variable hasLoaded is set to true before the fetched data is set. Can anybody help?


Solution

  • The problem is you return a function NOT a promise.
    This resolves immediately.

    See working code sample

    export const fetchData2 = dispatch => () => {
      dispatch({type: 'START_FETCH'})
      const p = [
        fetchDataSetOne(dispatch),
        fetchDataSetTwo(dispatch)
      ];
      Promise.all(p).then((res) => setHasLoaded(res));
    };
    
    // this returns a promise AFTER it calls an action
    const fetchDataSetOne = dispatch => {
      return axois.get(`${API_URL}/dataSetOne`).then(res => {
        dispatch({
          type: "FETCH_ALL_DATA_SET_ONE",
          payload: res.data.docs
        });
      });
    };

    This resolves after both promises are resolved, but the state updates after each promise is resolved. To update state after all promises resolve, try this:

    export const fetchData3 = dispatch => () => {
      dispatch({ type: "START_FETCH" });
      const p = [
        axois.get(`${API_URL}/dataSetOne`),
        axois.get(`${API_URL}/dataSetTwo`)
      ];
      Promise.all(p).then(callActions(dispatch));
    };
    
    const callActions = dispatch => res => {
      dispatch({
        type: "FETCH_ALL_DATA_SET_ONE",
        payload: res[0].data.docs
      });
      dispatch({
        type: "FETCH_ALL_DATA_SET_TWO",
        payload: res[1].data.docs
      });
      setHasLoaded(res);
    };