mirror of
https://github.com/prymitive/karma
synced 2026-05-09 03:36:44 +00:00
140 lines
3.2 KiB
TypeScript
140 lines
3.2 KiB
TypeScript
import { useState, useEffect, useCallback } from "react";
|
|
|
|
import merge from "lodash.merge";
|
|
|
|
import { CommonOptions } from "Common/Fetch";
|
|
|
|
export interface UpstreamT {
|
|
uri: string;
|
|
options: RequestInit;
|
|
}
|
|
|
|
export type FetchFunctionT = (
|
|
input: RequestInfo | URL,
|
|
init?: RequestInit | undefined
|
|
) => Promise<Response>;
|
|
|
|
export interface FetchAnyOptionsT {
|
|
fetcher?: null | FetchFunctionT;
|
|
}
|
|
|
|
interface ResponseState<T> {
|
|
response: T | null;
|
|
error: string | null;
|
|
responseURI: string | null;
|
|
inProgress: boolean;
|
|
}
|
|
|
|
const useFetchAny = <T>(
|
|
upstreams: UpstreamT[],
|
|
{ fetcher = null }: FetchAnyOptionsT = {}
|
|
): {
|
|
response: T | null;
|
|
error: string | null;
|
|
responseURI: string | null;
|
|
inProgress: boolean;
|
|
reset: () => void;
|
|
} => {
|
|
const [index, setIndex] = useState<number>(0);
|
|
const [response, setResponse] = useState<ResponseState<T>>({
|
|
response: null,
|
|
error: null,
|
|
responseURI: null,
|
|
inProgress: false,
|
|
});
|
|
|
|
const reset = useCallback(() => {
|
|
setIndex(0);
|
|
setResponse({
|
|
response: null,
|
|
error: null,
|
|
responseURI: null,
|
|
inProgress: false,
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// https://dev.to/pallymore/clean-up-async-requests-in-useeffect-hooks-90h
|
|
let isCancelled = false;
|
|
|
|
const fetchData = async () => {
|
|
const { uri, options } = upstreams[index];
|
|
|
|
setResponse({
|
|
response: null,
|
|
error: null,
|
|
responseURI: null,
|
|
inProgress: true,
|
|
});
|
|
try {
|
|
const res = await (fetcher || fetch)(
|
|
uri,
|
|
merge({}, { method: "GET" }, CommonOptions, options) as RequestInit
|
|
);
|
|
|
|
if (!isCancelled) {
|
|
let body;
|
|
const contentType = res.headers.get("content-type");
|
|
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
body = await res.json();
|
|
} else {
|
|
body = await res.text();
|
|
}
|
|
|
|
if (!isCancelled) {
|
|
if (res.ok) {
|
|
setResponse({
|
|
response: body,
|
|
error: null,
|
|
responseURI: uri,
|
|
inProgress: false,
|
|
});
|
|
} else {
|
|
if (upstreams.length > index + 1) {
|
|
setIndex(index + 1);
|
|
} else {
|
|
setResponse({
|
|
response: null,
|
|
error: body ? body : `${res.status} ${res.statusText}`,
|
|
responseURI: null,
|
|
inProgress: false,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (!isCancelled) {
|
|
if (upstreams.length > index + 1) {
|
|
setIndex(index + 1);
|
|
} else {
|
|
setResponse({
|
|
response: null,
|
|
error:
|
|
error instanceof Error
|
|
? error.message
|
|
: `unknown error: ${error}`,
|
|
responseURI: null,
|
|
inProgress: false,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (upstreams.length > 0) {
|
|
fetchData();
|
|
} else {
|
|
reset();
|
|
}
|
|
|
|
return () => {
|
|
isCancelled = true;
|
|
};
|
|
}, [upstreams, index, reset, fetcher]);
|
|
|
|
return { ...response, reset };
|
|
};
|
|
|
|
export { useFetchAny };
|