Custom hook to query an arbitrary number of services asynchronously and serially
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[]} services list of services (array of length n)
* @param {Object[]} params params for services (array of length n)
* @returns {Array} Returns an array with [result, isLoading, isError]
*
* - Initial values: [false, false, []]
* - isError is false if one service fails.
* - isLoading will return true until all services completes
* - result is an array of length n
*/
function useFetchSerial(services, params) {
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);
if (typeof params === 'undefined') {
params = services.map((s) => null);
}
useEffect(() => {
const fetchData = async () => {
try {
dispatch({type: A_FETCH_INIT});
let res = [];
for (let i = 0; i < services.length; i++) {
let r = await services[i](params[i]);
res.push(r);
}
dispatch({type: A_FETCH_SUCCESS, data: res});
} catch (error) {
dispatch({type: A_FETCH_FAILURE});
}
};
if (state.result === null && !state.isLoading && !state.isError) {
fetchData();
}
}, [services, params, state.result, state.isError, state.isLoading]);
return [state.result, state.isLoading, state.isError];
}
export {useFetchSerial};