Search code examples
javascriptreactjsreduxredux-thunk

What is the better/correct way of using Promise.all with React-Redux-Thunk?


export const FETCH_DB_BEGIN = 'FETCH_DB_BEGIN'
export const FETCH_DB_SUCCESS = 'FETCH_DB_SUCCESS'
export const FETCH_DB_FAILURE = 'FETCH_DB_FAILURE'

export const fetchDatabase = () => {
    return dispatch => {
        const profile_url = 'localhost:5000/profiles'
        const release_url = 'localhost:5000/releases'
        const emp_url = 'localhost:5000/users'
        let promises = []

        let options = {
            headers: header,
            method: 'get',
            mode: 'cors',
            body: null,
        }
        dispatch(fetchDbBegin());

        // run the script async. change state when it's done.
        let profile_promise = new Promise((resolve, reject) => {
            fetch(profile_url, options)
                .then(res => res.json())
                .then(resText => {
                    // Use Dispatch Here?
                })
        }).catch(err => {
            console.log(err)
        })
        promises.push(profile_promise)

        // run the script async. change state when it's done.
        let release_promise = new Promise((resolve, reject) => {
            fetch(release_url, options)
                .then(res => res.json())
                .then(resText => {
                })
        }).catch(err => {
            console.log(err)
        })
        promises.push(release_promise)

        // run the script async. change state when it's done.
        let emp_promise = new Promise((resolve, reject) => {
            fetch(emp_url, options)
                .then(res => res.json())
                .then(resText => {

                })
        }).catch(err => {
            console.log(err)
        })
        promises.push(emp_promise)

        Promise.all(promises).then(values => {
            console.log(values)
        })
    }
}

export const fetchDbBegin = () => ({
    type: FETCH_DB_BEGIN
});

export const fetchDbSuccess = (data) => ({
    type: FETCH_DB_SUCCESS,
    payload: { data }
});

export const fetchDbFailure = (err) => ({
    type: FETCH_DB_FAILURE,
    payload: { err }
});

I am in a process of refactoring a React class component to use Redux. It initially had all API calls inside the componentDidMount and it was so messy.

I am using redux-thunk to move this out from the class component.

The fetchDatabase in my databaseAction.js does everything that componentDidMount did in the class component.

Normally if it was a single API call, I would have just dispatched the fetchDbSuccess as the API call was done successfully. However, using Promise.All which takes three async API calls, I am not sure whether I should

  1. create a separate action for each API call (fetchProfileSuccess, fetchReleaseSuccess, and fetchUserSuccess) and dispatch each one of them at the end of each Promise (the place where I put //Use Dispatch Here? in the code.

OR

  1. Just dispatch single fetchDbSuccess when the Promise.all gets resolved.

If I choose to do 2, am I supposed to update all three states in my reducer?

Thanks


Solution

  • You should only dispatch and update state if you have code that cares about said state updates. For example, if you're just wanting to show a single spinner then have the spinner go away when fully completed, your user doesn't necessarily care about each atomic operation, so you don't need it reflected in state. If you have a UI that does show each, then you would want those extra dispatches.

    By the way, your Promises look a bit overcomplicated. If you decide you don't need those extra state changes, you can simplify to this:

    export const FETCH_DB_BEGIN = 'FETCH_DB_BEGIN'
    export const FETCH_DB_SUCCESS = 'FETCH_DB_SUCCESS'
    export const FETCH_DB_FAILURE = 'FETCH_DB_FAILURE'
    
    export const fetchDatabase = () => {
        return dispatch => {
            dispatch(fetchDbBegin());
    
            const urls = [
                'http://localhost:5000/profiles',
                'http://localhost:5000/releases',
                'http://localhost:5000/users'
            ];
    
            const options = {
                headers: header,
                method: 'get',
                mode: 'cors',
                body: null,
            }
    
            const fetchJson = url => fetch(url, options).then(res => res.json());
    
            Promise.all(urls.map(fetchJson))
                .then(([profile, release, employee]) => {
                    dispatch(fetchDbSuccess({ profile, release, employee }));
                })
                .catch(err => {
                    dispatch(fetchDbFailure(err));
                });
        }
    }
    
    export const fetchDbBegin = () => ({
        type: FETCH_DB_BEGIN
    });
    
    export const fetchDbSuccess = (data) => ({
        type: FETCH_DB_SUCCESS,
        payload: { data }
    });
    
    export const fetchDbFailure = (err) => ({
        type: FETCH_DB_FAILURE,
        payload: { err }
    });