@hyper-fetch/react
Version:
React hooks and utils for the hyper-fetch
109 lines (96 loc) • 3.03 kB
text/typescript
import { useDidUpdate } from "@better-hooks/lifecycle";
import type { RequestInstance } from "@hyper-fetch/core";
import { getRequestDispatcher } from "@hyper-fetch/core";
import { useRef } from "react";
import type { UseCacheOptionsType, UseCacheReturnType } from "hooks/use-cache";
import { useCacheDefaultOptions } from "hooks/use-cache";
import { useRequestEvents, useTrackedState } from "helpers";
import { useProvider } from "provider";
import { createTrackedProxy } from "utils";
/** Subscribe to cache updates for a given request without triggering network activity. */
export const useCache = <T extends RequestInstance>(
request: T,
options?: UseCacheOptionsType<T>,
): UseCacheReturnType<T> => {
const { cacheKey, client } = request;
const { cache, loggerManager } = client;
const logger = useRef(loggerManager.initialize(client, "useCache")).current;
const [dispatcher] = getRequestDispatcher(request);
const updateKey = JSON.stringify(request.toJSON());
// Build the configuration options
const { config: globalConfig } = useProvider();
const { dependencyTracking, initialResponse, deepCompare } = {
...useCacheDefaultOptions,
...globalConfig.useCacheConfig,
...options,
};
/**
* State handler with optimization for rerendering, that hooks into the cache state and dispatchers queues
*/
const [state, actions, { setRenderKey, setCacheData, getIsDataProcessing }] = useTrackedState<T>({
logger,
request,
dispatcher,
initialResponse,
deepCompare,
dependencyTracking,
});
/**
* Handles the data exchange with the core logic - responses, loading, downloading etc
*/
const [, listeners] = useRequestEvents({
logger,
actions,
request,
dispatcher,
setCacheData,
getIsDataProcessing,
});
const { addCacheDataListener, addLifecycleListeners } = listeners;
const handleMountEvents = () => {
const unmountDataListener = addCacheDataListener(request);
const unmountLifecycleListener = addLifecycleListeners(request);
return () => {
unmountDataListener();
unmountLifecycleListener();
};
};
useDidUpdate(
() => {
return handleMountEvents();
},
[updateKey],
true,
);
const invalidate = (cacheKeys?: string | RegExp | RequestInstance | Array<string | RegExp | RequestInstance>) => {
cache.invalidate(cacheKeys ?? cacheKey);
};
const trackedKeys = [
"data",
"error",
"loading",
"status",
"success",
"extra",
"retries",
"responseTimestamp",
"requestTimestamp",
] as const;
return createTrackedProxy(
{
data: state.data,
error: state.error,
loading: state.loading,
status: state.status,
success: state.success,
extra: state.extra,
retries: state.retries,
responseTimestamp: state.responseTimestamp,
requestTimestamp: state.requestTimestamp,
...actions,
invalidate,
},
trackedKeys,
setRenderKey,
) as UseCacheReturnType<T>;
};