@hyper-fetch/react
Version:
React hooks and utils for the hyper-fetch
113 lines (89 loc) • 3.58 kB
text/typescript
import { useState, useRef } from "react";
import { RequestInstance, getRequestDispatcher, QueueElementType } from "@hyper-fetch/core";
import { useDidMount, useDidUpdate } from "@better-hooks/lifecycle";
import { UseQueueOptionsType, useQueueDefaultOptions, QueueRequest, UseQueueReturnType } from "hooks/use-queue";
import { useConfigProvider } from "config-provider";
/**
* This hook allows to control dispatchers request queues
* @param request
* @param options
* @returns
*/
export const useQueue = <Request extends RequestInstance>(
request: Request,
options: UseQueueOptionsType = useQueueDefaultOptions,
): UseQueueReturnType<Request> => {
// Build the configuration options
const [globalConfig] = useConfigProvider();
const { queueType = "auto" } = {
...useQueueDefaultOptions,
...globalConfig.useQueueConfig,
...options,
};
const { abortKey, queueKey, client } = request;
const { requestManager } = client;
const [dispatcher] = getRequestDispatcher(request, queueType);
const unmountCallbacks = useRef<null | VoidFunction>(null);
const [stopped, setStopped] = useState(false);
const [requests, setRequests] = useState<QueueRequest<Request>[]>([]);
// ******************
// Mapping
// ******************
const createRequestsArray = (queueElements: QueueElementType<Request>[]): QueueRequest<Request>[] => {
return queueElements.map<QueueRequest<Request>>((req) => ({
...req,
stopRequest: () => dispatcher.stopRequest(queueKey, req.requestId),
startRequest: () => dispatcher.startRequest(queueKey, req.requestId),
deleteRequest: () => dispatcher.delete(queueKey, req.requestId, abortKey),
}));
};
const mergePayloadType = (requestId: string, data: Partial<QueueRequest<Request>>) => {
setRequests((prev) => prev.map((el) => (el.requestId === requestId ? { ...el, ...data } : el)));
};
// ******************
// State
// ******************
const getInitialState = () => {
const requestQueue = dispatcher.getQueue<Request>(queueKey);
setStopped(requestQueue.stopped);
setRequests(createRequestsArray(requestQueue.requests));
};
const updateQueueState = (values: { requests: QueueRequest<Request>[]; stopped: boolean }) => {
setStopped(values.stopped);
setRequests(createRequestsArray(values.requests));
};
// ******************
// Events
// ******************
const mountEvents = () => {
const unmountChange = dispatcher.events.onQueueChange<Request>(queueKey, updateQueueState);
const unmountStatus = dispatcher.events.onQueueStatus<Request>(queueKey, updateQueueState);
const unmountDownload = requestManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => {
mergePayloadType(requestId, { downloading: progress });
});
const unmountUpload = requestManager.events.onUploadProgress(queueKey, (progress, { requestId }) => {
mergePayloadType(requestId, { uploading: progress });
});
const unmount = () => {
unmountStatus();
unmountChange();
unmountDownload();
unmountUpload();
};
unmountCallbacks.current?.();
unmountCallbacks.current = unmount;
return unmount;
};
// ******************
// Lifecycle
// ******************
useDidMount(getInitialState);
useDidUpdate(mountEvents, [stopped, requests, setRequests, setStopped], true);
return {
stopped,
requests,
stop: () => dispatcher.stop(queueKey),
pause: () => dispatcher.pause(queueKey),
start: () => dispatcher.start(queueKey),
};
};