Last active
November 5, 2020 15:49
-
-
Save brunopk/5577fafcc37c883cdb5bfdb761eca3a5 to your computer and use it in GitHub Desktop.
Custom hook to query an arbitrary number of services asynchronously and parallelly using promises and async-await
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {useReducer, useEffect} from 'react'; | |
const A_FETCH_INIT = 'FETCH_INIT'; | |
const A_FETCH_SUCCESS = 'FETCH_SUCCESS'; | |
const A_FETCH_FAILURE = 'FETCH_FAILURE'; | |
const INITIAL_STATE = { | |
isLoading: false, | |
isError: false, | |
result: null, | |
}; | |
/** | |
* Query a list of services asynchronously. | |
* @param {Function[]} service list of services (none of them receive params) | |
* @returns {Array} Returns an array with [isLoading, isError, result] | |
* | |
* - Initial values: [false, false, []] | |
* - isError returns false if one service fails. | |
* - isLoading will return true until all services completes | |
* - result is an array with same length as services array | |
*/ | |
function useFetchParallel(services) { | |
const [state, dispatch] = useReducer((prevState, action) => { | |
switch (action.type) { | |
case A_FETCH_SUCCESS: | |
return { | |
...prevState, | |
isLoading: false, | |
result: action.data, | |
}; | |
case A_FETCH_FAILURE: | |
return { | |
...prevState, | |
isError: true, | |
isLoading: false, | |
}; | |
case A_FETCH_INIT: | |
return { | |
...prevState, | |
isLoading: true, | |
isError: false, | |
}; | |
default: | |
return INITIAL_STATE; | |
} | |
}, INITIAL_STATE); | |
useEffect(() => { | |
const fetchData = async () => { | |
try { | |
dispatch({type: A_FETCH_INIT}); | |
// One promise fail , all promise fail ! | |
let res = await Promise.all( | |
services.map( | |
(s) => | |
new Promise(async (resolve, reject) => { | |
try { | |
let r = await s(); | |
resolve(r); | |
} catch (error) { | |
reject(error); | |
} | |
}), | |
), | |
); | |
dispatch({type: A_FETCH_SUCCESS, data: res}); | |
} catch (error) { | |
console.log(error); | |
dispatch({type: A_FETCH_FAILURE}); | |
} | |
}; | |
if (state.result === null && !state.isLoading && !state.isError) { | |
fetchData(); | |
} | |
}, [services, state.result, state.isLoading, state.isError]); | |
return [state.result, state.isLoading, state.isError]; | |
} | |
export {useFetchParallel}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment