Skip to content

Instantly share code, notes, and snippets.

@dev-drprasad
Created August 4, 2020 11:01
Show Gist options
  • Save dev-drprasad/27818278cbafa87dd212ecc91de8adf4 to your computer and use it in GitHub Desktop.
Save dev-drprasad/27818278cbafa87dd212ecc91de8adf4 to your computer and use it in GitHub Desktop.
function useMultiFetch<T>(args: [string, RequestInit][]) {
const [response, setResponse] = useState([] as [T | undefined, NS][]);
const ref = useRef([] as [T | undefined, NS][]);
const abortRef = useRef([] as AbortController[]);
useEffect(() => {
if (args.length === 0) return;
const lendiff = args.length - ref.current.length;
if (lendiff < 0) {
ref.current = ref.current.slice(0, lendiff);
const notneeded = abortRef.current.slice(lendiff);
notneeded.forEach((ctrl) => ctrl.abort());
abortRef.current = abortRef.current.slice(0, lendiff);
setResponse(response.slice(0, lendiff));
} else {
ref.current = ref.current.concat(Array(lendiff).fill(undefined));
abortRef.current = abortRef.current.concat(Array(lendiff).fill(undefined));
setResponse(response.concat(Array(lendiff).fill([undefined, new NS("INIT")])));
}
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (deepequal(arg, ref.current[i])) continue;
if (abortRef.current[i]) abortRef.current[i].abort();
abortRef.current[i] = new AbortController();
const front = response.slice(0, i);
const behind = response.slice(i + 1);
setResponse([...front, [undefined, new NS("LOADING")], ...behind]);
const [url, options] = arg;
const startTime = performance.now();
fetch(url, { ...defaultFetchOptions, ...options, signal: abortRef.current[i].signal })
.then(async (res) => {
const responseTime = performance.now() - startTime;
const reqEndTime = Date.now();
const cached = !!res.headers.get("X-Browser-Cache");
let body: any;
try {
body = await res.json();
} catch (e) {
const message = "Invalid JSON response from API";
console.error(
`${cr}API Error:${cr}${tab}URL: ${url}${cr}${tab}Msg: ${message}${cr}${tab}Code: ${res.status}`
);
setResponse([
...front,
[undefined, new NS("ERROR", defaultErrorMessage, res.status, responseTime, reqEndTime, cached)],
...behind,
]);
return;
}
if (res.status >= 400) {
const errorType: string = body.error || "";
const isInternalError = !errorType || errorType === "Internal Server Error";
const message: string = !isInternalError ? body.message || defaultErrorMessage : defaultErrorMessage;
setResponse([
...front,
[undefined, new NS("ERROR", message, res.status, responseTime, reqEndTime, cached)],
...behind,
]);
return;
}
const dataType = getType(body);
const hasData = dataType !== "Null" && (dataType === "Array" ? body.length > 0 : true);
setResponse([
...front,
[body, new NS("SUCCESS", "", res.status, responseTime, reqEndTime, cached, hasData)],
...behind,
]);
})
.catch((err: Error) => {
const responseTime = performance.now() - startTime;
const requestEndTime = Date.now();
console.error(`${cr}API Error:${cr}${tab}URL: ${url}${cr}${tab}Msg: ${err.message}${cr}${tab}Code: 0`);
setResponse([
...front,
[undefined, new NS("ERROR", err.message, 0, responseTime, requestEndTime)],
...behind,
]);
});
}
}, [args]);
return response;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment