@hookraft/userequest 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +6 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +6 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -81,9 +81,8 @@ function useRequest(key, options = {}) {
|
|
|
81
81
|
onStatusChange
|
|
82
82
|
} = options;
|
|
83
83
|
const [data, setData] = (0, import_react.useState)(() => {
|
|
84
|
-
var _a;
|
|
85
84
|
if (!key) return void 0;
|
|
86
|
-
return
|
|
85
|
+
return getCached(key, cacheTime) ?? void 0;
|
|
87
86
|
});
|
|
88
87
|
const [status, setStatus] = (0, import_react.useState)(() => {
|
|
89
88
|
if (!key) return "idle";
|
|
@@ -111,14 +110,12 @@ function useRequest(key, options = {}) {
|
|
|
111
110
|
};
|
|
112
111
|
}, []);
|
|
113
112
|
const updateStatus = (0, import_react.useCallback)((next) => {
|
|
114
|
-
var _a;
|
|
115
113
|
if (!mountedRef.current) return;
|
|
116
114
|
setStatus(next);
|
|
117
|
-
|
|
115
|
+
onStatusChangeRef.current?.(next);
|
|
118
116
|
}, []);
|
|
119
117
|
const execute = (0, import_react.useCallback)(
|
|
120
118
|
async (forceRefresh = false) => {
|
|
121
|
-
var _a, _b, _c, _d;
|
|
122
119
|
if (!key) return;
|
|
123
120
|
if (!forceRefresh) {
|
|
124
121
|
const cached = getCached(key, cacheTime);
|
|
@@ -141,12 +138,12 @@ function useRequest(key, options = {}) {
|
|
|
141
138
|
if (!mountedRef.current) return;
|
|
142
139
|
setData(result);
|
|
143
140
|
updateStatus("success");
|
|
144
|
-
|
|
141
|
+
onSuccessRef.current?.(result);
|
|
145
142
|
} catch (err) {
|
|
146
143
|
if (!mountedRef.current) return;
|
|
147
144
|
setError(err);
|
|
148
145
|
updateStatus("error");
|
|
149
|
-
|
|
146
|
+
onErrorRef.current?.(err);
|
|
150
147
|
}
|
|
151
148
|
return;
|
|
152
149
|
}
|
|
@@ -164,13 +161,13 @@ function useRequest(key, options = {}) {
|
|
|
164
161
|
setData(result);
|
|
165
162
|
setError(void 0);
|
|
166
163
|
updateStatus("success");
|
|
167
|
-
|
|
164
|
+
onSuccessRef.current?.(result);
|
|
168
165
|
} catch (err) {
|
|
169
166
|
clearInFlight(key);
|
|
170
167
|
if (!mountedRef.current) return;
|
|
171
168
|
setError(err);
|
|
172
169
|
updateStatus("error");
|
|
173
|
-
|
|
170
|
+
onErrorRef.current?.(err);
|
|
174
171
|
}
|
|
175
172
|
},
|
|
176
173
|
[key, cacheTime, dedupe, fetcher, updateStatus]
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useRequest.ts","../src/store.ts"],"sourcesContent":["export { useRequest } from \"./useRequest\"\nexport { clearAll } from \"./store\"\nexport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n CacheEntry,\n} from \"./types\"","import { useState, useEffect, useCallback, useRef } from \"react\"\nimport {\n getCached,\n setCached,\n clearCached,\n getInFlight,\n setInFlight,\n clearInFlight,\n} from \"./store\"\nimport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n} from \"./types\"\n\nconst defaultFetcher = (key: string) =>\n fetch(key).then((res) => {\n if (!res.ok) throw new Error(`Request failed: ${res.status} ${res.statusText}`)\n return res.json()\n })\n\n/**\n * useRequest\n *\n * A deduplication-first data fetching hook.\n * Multiple components requesting the same key at the same time\n * will share a single in-flight request — not fire multiple.\n *\n * All caching is in-memory only (JS RAM). Nothing is written\n * to localStorage, sessionStorage, or any browser storage.\n *\n * @example\n * // All three components share ONE network request\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n */\nexport function useRequest<T = unknown>(\n key: string | null,\n options: UseRequestOptions<T> = {}\n): UseRequestReturn<T> {\n const {\n fetcher = defaultFetcher as (key: string) => Promise<T>,\n cacheTime = 30_000,\n dedupe = true,\n manual = false,\n onSuccess,\n onError,\n onStatusChange,\n } = options\n\n const [data, setData] = useState<T | undefined>(() => {\n if (!key) return undefined\n return getCached<T>(key, cacheTime) ?? undefined\n })\n const [status, setStatus] = useState<RequestStatus>(() => {\n if (!key) return \"idle\"\n const cached = getCached<T>(key, cacheTime)\n return cached !== null ? \"success\" : \"idle\"\n })\n const [error, setError] = useState<unknown>(undefined)\n\n const mountedRef = useRef(true)\n const onSuccessRef = useRef(onSuccess)\n const onErrorRef = useRef(onError)\n const onStatusChangeRef = useRef(onStatusChange)\n\n // Keep callback refs fresh without causing re-runs\n useEffect(() => { onSuccessRef.current = onSuccess }, [onSuccess])\n useEffect(() => { onErrorRef.current = onError }, [onError])\n useEffect(() => { onStatusChangeRef.current = onStatusChange }, [onStatusChange])\n\n useEffect(() => {\n mountedRef.current = true\n return () => { mountedRef.current = false }\n }, [])\n\n const updateStatus = useCallback((next: RequestStatus) => {\n if (!mountedRef.current) return\n setStatus(next)\n onStatusChangeRef.current?.(next)\n }, [])\n\n const execute = useCallback(\n async (forceRefresh = false): Promise<void> => {\n if (!key) return\n\n // Check cache first (unless force refreshing)\n if (!forceRefresh) {\n const cached = getCached<T>(key, cacheTime)\n if (cached !== null) {\n if (mountedRef.current) {\n setData(cached)\n updateStatus(\"success\")\n }\n return\n }\n } else {\n clearCached(key)\n }\n\n // Check for an in-flight request for this key\n if (dedupe) {\n const existing = getInFlight<T>(key)\n if (existing) {\n updateStatus(\"loading\")\n try {\n const result = await existing\n if (!mountedRef.current) return\n setData(result)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n return\n }\n }\n\n // No cache, no in-flight — fire a new request\n updateStatus(\"loading\")\n\n const promise = fetcher(key)\n\n if (dedupe) {\n setInFlight(key, promise)\n }\n\n try {\n const result = await promise\n setCached(key, result)\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setData(result)\n setError(undefined)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n },\n [key, cacheTime, dedupe, fetcher, updateStatus]\n )\n\n // Auto-fetch on mount unless manual mode\n useEffect(() => {\n if (!key || manual) return\n execute()\n }, [key, manual, execute])\n\n const refetch = useCallback(async () => {\n await execute(true)\n }, [execute])\n\n const clear = useCallback(() => {\n if (!key) return\n clearCached(key)\n setData(undefined)\n setError(undefined)\n updateStatus(\"idle\")\n }, [key, updateStatus])\n\n const is = useCallback(\n (s: RequestStatus) => status === s,\n [status]\n )\n\n return {\n data,\n status,\n error,\n isLoading: status === \"loading\",\n isSuccess: status === \"success\",\n isError: status === \"error\",\n is,\n refetch,\n clear,\n }\n}","import type { CacheEntry, InFlightEntry } from \"./types\"\n\n/**\n * Global in-memory cache — lives in JS RAM only.\n * Never touches localStorage, sessionStorage, or any browser storage.\n * Cleared automatically when the page refreshes or tab closes.\n */\nconst cache = new Map<string, CacheEntry<unknown>>()\n\n/**\n * In-flight registry — tracks requests currently in progress.\n * If a request for the same key is already in flight,\n * new subscribers attach to the existing Promise instead of firing a new request.\n */\nconst inFlight = new Map<string, InFlightEntry<unknown>>()\n\nexport function getCached<T>(key: string, cacheTime: number): T | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined\n if (!entry) return null\n if (cacheTime === 0) return null\n const isStale = Date.now() - entry.timestamp > cacheTime\n if (isStale) {\n cache.delete(key)\n return null\n }\n return entry.data\n}\n\nexport function setCached<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() })\n}\n\nexport function clearCached(key: string): void {\n cache.delete(key)\n}\n\nexport function getInFlight<T>(key: string): Promise<T> | null {\n const entry = inFlight.get(key) as InFlightEntry<T> | undefined\n if (!entry) return null\n entry.subscribers++\n return entry.promise\n}\n\nexport function setInFlight<T>(key: string, promise: Promise<T>): void {\n inFlight.set(key, { promise: promise as Promise<unknown>, subscribers: 1 })\n}\n\nexport function clearInFlight(key: string): void {\n inFlight.delete(key)\n}\n\nexport function clearAll(): void {\n cache.clear()\n inFlight.clear()\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useRequest.ts","../src/store.ts"],"sourcesContent":["export { useRequest } from \"./useRequest\"\nexport { clearAll } from \"./store\"\nexport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n CacheEntry,\n} from \"./types\"","import { useState, useEffect, useCallback, useRef } from \"react\"\nimport {\n getCached,\n setCached,\n clearCached,\n getInFlight,\n setInFlight,\n clearInFlight,\n} from \"./store\"\nimport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n} from \"./types\"\n\nconst defaultFetcher = (key: string) =>\n fetch(key).then((res) => {\n if (!res.ok) throw new Error(`Request failed: ${res.status} ${res.statusText}`)\n return res.json()\n })\n\n/**\n * useRequest\n *\n * A deduplication-first data fetching hook.\n * Multiple components requesting the same key at the same time\n * will share a single in-flight request — not fire multiple.\n *\n * All caching is in-memory only (JS RAM). Nothing is written\n * to localStorage, sessionStorage, or any browser storage.\n *\n * @example\n * // All three components share ONE network request\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n */\nexport function useRequest<T = unknown>(\n key: string | null,\n options: UseRequestOptions<T> = {}\n): UseRequestReturn<T> {\n const {\n fetcher = defaultFetcher as (key: string) => Promise<T>,\n cacheTime = 30_000,\n dedupe = true,\n manual = false,\n onSuccess,\n onError,\n onStatusChange,\n } = options\n\n const [data, setData] = useState<T | undefined>(() => {\n if (!key) return undefined\n return getCached<T>(key, cacheTime) ?? undefined\n })\n const [status, setStatus] = useState<RequestStatus>(() => {\n if (!key) return \"idle\"\n const cached = getCached<T>(key, cacheTime)\n return cached !== null ? \"success\" : \"idle\"\n })\n const [error, setError] = useState<unknown>(undefined)\n\n const mountedRef = useRef(true)\n const onSuccessRef = useRef(onSuccess)\n const onErrorRef = useRef(onError)\n const onStatusChangeRef = useRef(onStatusChange)\n\n // Keep callback refs fresh without causing re-runs\n useEffect(() => { onSuccessRef.current = onSuccess }, [onSuccess])\n useEffect(() => { onErrorRef.current = onError }, [onError])\n useEffect(() => { onStatusChangeRef.current = onStatusChange }, [onStatusChange])\n\n useEffect(() => {\n mountedRef.current = true\n return () => { mountedRef.current = false }\n }, [])\n\n const updateStatus = useCallback((next: RequestStatus) => {\n if (!mountedRef.current) return\n setStatus(next)\n onStatusChangeRef.current?.(next)\n }, [])\n\n const execute = useCallback(\n async (forceRefresh = false): Promise<void> => {\n if (!key) return\n\n // Check cache first (unless force refreshing)\n if (!forceRefresh) {\n const cached = getCached<T>(key, cacheTime)\n if (cached !== null) {\n if (mountedRef.current) {\n setData(cached)\n updateStatus(\"success\")\n }\n return\n }\n } else {\n clearCached(key)\n }\n\n // Check for an in-flight request for this key\n if (dedupe) {\n const existing = getInFlight<T>(key)\n if (existing) {\n updateStatus(\"loading\")\n try {\n const result = await existing\n if (!mountedRef.current) return\n setData(result)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n return\n }\n }\n\n // No cache, no in-flight — fire a new request\n updateStatus(\"loading\")\n\n const promise = fetcher(key)\n\n if (dedupe) {\n setInFlight(key, promise)\n }\n\n try {\n const result = await promise\n setCached(key, result)\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setData(result)\n setError(undefined)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n },\n [key, cacheTime, dedupe, fetcher, updateStatus]\n )\n\n // Auto-fetch on mount unless manual mode\n useEffect(() => {\n if (!key || manual) return\n execute()\n }, [key, manual, execute])\n\n const refetch = useCallback(async () => {\n await execute(true)\n }, [execute])\n\n const clear = useCallback(() => {\n if (!key) return\n clearCached(key)\n setData(undefined)\n setError(undefined)\n updateStatus(\"idle\")\n }, [key, updateStatus])\n\n const is = useCallback(\n (s: RequestStatus) => status === s,\n [status]\n )\n\n return {\n data,\n status,\n error,\n isLoading: status === \"loading\",\n isSuccess: status === \"success\",\n isError: status === \"error\",\n is,\n refetch,\n clear,\n }\n}","import type { CacheEntry, InFlightEntry } from \"./types\"\n\n/**\n * Global in-memory cache — lives in JS RAM only.\n * Never touches localStorage, sessionStorage, or any browser storage.\n * Cleared automatically when the page refreshes or tab closes.\n */\nconst cache = new Map<string, CacheEntry<unknown>>()\n\n/**\n * In-flight registry — tracks requests currently in progress.\n * If a request for the same key is already in flight,\n * new subscribers attach to the existing Promise instead of firing a new request.\n */\nconst inFlight = new Map<string, InFlightEntry<unknown>>()\n\nexport function getCached<T>(key: string, cacheTime: number): T | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined\n if (!entry) return null\n if (cacheTime === 0) return null\n const isStale = Date.now() - entry.timestamp > cacheTime\n if (isStale) {\n cache.delete(key)\n return null\n }\n return entry.data\n}\n\nexport function setCached<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() })\n}\n\nexport function clearCached(key: string): void {\n cache.delete(key)\n}\n\nexport function getInFlight<T>(key: string): Promise<T> | null {\n const entry = inFlight.get(key) as InFlightEntry<T> | undefined\n if (!entry) return null\n entry.subscribers++\n return entry.promise\n}\n\nexport function setInFlight<T>(key: string, promise: Promise<T>): void {\n inFlight.set(key, { promise: promise as Promise<unknown>, subscribers: 1 })\n}\n\nexport function clearInFlight(key: string): void {\n inFlight.delete(key)\n}\n\nexport function clearAll(): void {\n cache.clear()\n inFlight.clear()\n}"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type RequestStatus = "idle" | "loading" | "success" | "error";
|
|
2
|
+
interface CacheEntry<T> {
|
|
3
|
+
data: T;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
error?: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface UseRequestOptions<T> {
|
|
8
|
+
/**
|
|
9
|
+
* Custom fetcher function. Receives the key and returns a promise.
|
|
10
|
+
* Defaults to a basic fetch + json parse.
|
|
11
|
+
*/
|
|
12
|
+
fetcher?: (key: string) => Promise<T>;
|
|
13
|
+
/**
|
|
14
|
+
* How long in ms to keep data in cache before considering it stale.
|
|
15
|
+
* Defaults to 30000 (30 seconds). Set to 0 to disable caching.
|
|
16
|
+
*/
|
|
17
|
+
cacheTime?: number;
|
|
18
|
+
/**
|
|
19
|
+
* If true, deduplicates in-flight requests across all components.
|
|
20
|
+
* Defaults to true.
|
|
21
|
+
*/
|
|
22
|
+
dedupe?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* If true, the request will not fire automatically on mount.
|
|
25
|
+
* Call refetch() manually to trigger it.
|
|
26
|
+
*/
|
|
27
|
+
manual?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Fires when the request succeeds with the response data.
|
|
30
|
+
*/
|
|
31
|
+
onSuccess?: (data: T) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Fires when the request fails with the error.
|
|
34
|
+
*/
|
|
35
|
+
onError?: (error: unknown) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Fires whenever status changes.
|
|
38
|
+
*/
|
|
39
|
+
onStatusChange?: (status: RequestStatus) => void;
|
|
40
|
+
}
|
|
41
|
+
interface UseRequestReturn<T> {
|
|
42
|
+
/** The response data — undefined until request succeeds */
|
|
43
|
+
data: T | undefined;
|
|
44
|
+
/** Current request status */
|
|
45
|
+
status: RequestStatus;
|
|
46
|
+
/** Error if request failed */
|
|
47
|
+
error: unknown;
|
|
48
|
+
/** True while request is in flight */
|
|
49
|
+
isLoading: boolean;
|
|
50
|
+
/** True if request completed successfully */
|
|
51
|
+
isSuccess: boolean;
|
|
52
|
+
/** True if request failed */
|
|
53
|
+
isError: boolean;
|
|
54
|
+
/** Check current status */
|
|
55
|
+
is: (status: RequestStatus) => boolean;
|
|
56
|
+
/** Manually trigger a fresh request — bypasses cache */
|
|
57
|
+
refetch: () => Promise<void>;
|
|
58
|
+
/** Clear the cache for this key */
|
|
59
|
+
clear: () => void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* useRequest
|
|
64
|
+
*
|
|
65
|
+
* A deduplication-first data fetching hook.
|
|
66
|
+
* Multiple components requesting the same key at the same time
|
|
67
|
+
* will share a single in-flight request — not fire multiple.
|
|
68
|
+
*
|
|
69
|
+
* All caching is in-memory only (JS RAM). Nothing is written
|
|
70
|
+
* to localStorage, sessionStorage, or any browser storage.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // All three components share ONE network request
|
|
74
|
+
* const { data } = useRequest("/api/user")
|
|
75
|
+
* const { data } = useRequest("/api/user")
|
|
76
|
+
* const { data } = useRequest("/api/user")
|
|
77
|
+
*/
|
|
78
|
+
declare function useRequest<T = unknown>(key: string | null, options?: UseRequestOptions<T>): UseRequestReturn<T>;
|
|
79
|
+
|
|
80
|
+
declare function clearAll(): void;
|
|
81
|
+
|
|
82
|
+
export { type CacheEntry, type RequestStatus, type UseRequestOptions, type UseRequestReturn, clearAll, useRequest };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type RequestStatus = "idle" | "loading" | "success" | "error";
|
|
2
|
+
interface CacheEntry<T> {
|
|
3
|
+
data: T;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
error?: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface UseRequestOptions<T> {
|
|
8
|
+
/**
|
|
9
|
+
* Custom fetcher function. Receives the key and returns a promise.
|
|
10
|
+
* Defaults to a basic fetch + json parse.
|
|
11
|
+
*/
|
|
12
|
+
fetcher?: (key: string) => Promise<T>;
|
|
13
|
+
/**
|
|
14
|
+
* How long in ms to keep data in cache before considering it stale.
|
|
15
|
+
* Defaults to 30000 (30 seconds). Set to 0 to disable caching.
|
|
16
|
+
*/
|
|
17
|
+
cacheTime?: number;
|
|
18
|
+
/**
|
|
19
|
+
* If true, deduplicates in-flight requests across all components.
|
|
20
|
+
* Defaults to true.
|
|
21
|
+
*/
|
|
22
|
+
dedupe?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* If true, the request will not fire automatically on mount.
|
|
25
|
+
* Call refetch() manually to trigger it.
|
|
26
|
+
*/
|
|
27
|
+
manual?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Fires when the request succeeds with the response data.
|
|
30
|
+
*/
|
|
31
|
+
onSuccess?: (data: T) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Fires when the request fails with the error.
|
|
34
|
+
*/
|
|
35
|
+
onError?: (error: unknown) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Fires whenever status changes.
|
|
38
|
+
*/
|
|
39
|
+
onStatusChange?: (status: RequestStatus) => void;
|
|
40
|
+
}
|
|
41
|
+
interface UseRequestReturn<T> {
|
|
42
|
+
/** The response data — undefined until request succeeds */
|
|
43
|
+
data: T | undefined;
|
|
44
|
+
/** Current request status */
|
|
45
|
+
status: RequestStatus;
|
|
46
|
+
/** Error if request failed */
|
|
47
|
+
error: unknown;
|
|
48
|
+
/** True while request is in flight */
|
|
49
|
+
isLoading: boolean;
|
|
50
|
+
/** True if request completed successfully */
|
|
51
|
+
isSuccess: boolean;
|
|
52
|
+
/** True if request failed */
|
|
53
|
+
isError: boolean;
|
|
54
|
+
/** Check current status */
|
|
55
|
+
is: (status: RequestStatus) => boolean;
|
|
56
|
+
/** Manually trigger a fresh request — bypasses cache */
|
|
57
|
+
refetch: () => Promise<void>;
|
|
58
|
+
/** Clear the cache for this key */
|
|
59
|
+
clear: () => void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* useRequest
|
|
64
|
+
*
|
|
65
|
+
* A deduplication-first data fetching hook.
|
|
66
|
+
* Multiple components requesting the same key at the same time
|
|
67
|
+
* will share a single in-flight request — not fire multiple.
|
|
68
|
+
*
|
|
69
|
+
* All caching is in-memory only (JS RAM). Nothing is written
|
|
70
|
+
* to localStorage, sessionStorage, or any browser storage.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // All three components share ONE network request
|
|
74
|
+
* const { data } = useRequest("/api/user")
|
|
75
|
+
* const { data } = useRequest("/api/user")
|
|
76
|
+
* const { data } = useRequest("/api/user")
|
|
77
|
+
*/
|
|
78
|
+
declare function useRequest<T = unknown>(key: string | null, options?: UseRequestOptions<T>): UseRequestReturn<T>;
|
|
79
|
+
|
|
80
|
+
declare function clearAll(): void;
|
|
81
|
+
|
|
82
|
+
export { type CacheEntry, type RequestStatus, type UseRequestOptions, type UseRequestReturn, clearAll, useRequest };
|
package/dist/index.js
CHANGED
|
@@ -54,9 +54,8 @@ function useRequest(key, options = {}) {
|
|
|
54
54
|
onStatusChange
|
|
55
55
|
} = options;
|
|
56
56
|
const [data, setData] = useState(() => {
|
|
57
|
-
var _a;
|
|
58
57
|
if (!key) return void 0;
|
|
59
|
-
return
|
|
58
|
+
return getCached(key, cacheTime) ?? void 0;
|
|
60
59
|
});
|
|
61
60
|
const [status, setStatus] = useState(() => {
|
|
62
61
|
if (!key) return "idle";
|
|
@@ -84,14 +83,12 @@ function useRequest(key, options = {}) {
|
|
|
84
83
|
};
|
|
85
84
|
}, []);
|
|
86
85
|
const updateStatus = useCallback((next) => {
|
|
87
|
-
var _a;
|
|
88
86
|
if (!mountedRef.current) return;
|
|
89
87
|
setStatus(next);
|
|
90
|
-
|
|
88
|
+
onStatusChangeRef.current?.(next);
|
|
91
89
|
}, []);
|
|
92
90
|
const execute = useCallback(
|
|
93
91
|
async (forceRefresh = false) => {
|
|
94
|
-
var _a, _b, _c, _d;
|
|
95
92
|
if (!key) return;
|
|
96
93
|
if (!forceRefresh) {
|
|
97
94
|
const cached = getCached(key, cacheTime);
|
|
@@ -114,12 +111,12 @@ function useRequest(key, options = {}) {
|
|
|
114
111
|
if (!mountedRef.current) return;
|
|
115
112
|
setData(result);
|
|
116
113
|
updateStatus("success");
|
|
117
|
-
|
|
114
|
+
onSuccessRef.current?.(result);
|
|
118
115
|
} catch (err) {
|
|
119
116
|
if (!mountedRef.current) return;
|
|
120
117
|
setError(err);
|
|
121
118
|
updateStatus("error");
|
|
122
|
-
|
|
119
|
+
onErrorRef.current?.(err);
|
|
123
120
|
}
|
|
124
121
|
return;
|
|
125
122
|
}
|
|
@@ -137,13 +134,13 @@ function useRequest(key, options = {}) {
|
|
|
137
134
|
setData(result);
|
|
138
135
|
setError(void 0);
|
|
139
136
|
updateStatus("success");
|
|
140
|
-
|
|
137
|
+
onSuccessRef.current?.(result);
|
|
141
138
|
} catch (err) {
|
|
142
139
|
clearInFlight(key);
|
|
143
140
|
if (!mountedRef.current) return;
|
|
144
141
|
setError(err);
|
|
145
142
|
updateStatus("error");
|
|
146
|
-
|
|
143
|
+
onErrorRef.current?.(err);
|
|
147
144
|
}
|
|
148
145
|
},
|
|
149
146
|
[key, cacheTime, dedupe, fetcher, updateStatus]
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useRequest.ts","../src/store.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\"\nimport {\n getCached,\n setCached,\n clearCached,\n getInFlight,\n setInFlight,\n clearInFlight,\n} from \"./store\"\nimport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n} from \"./types\"\n\nconst defaultFetcher = (key: string) =>\n fetch(key).then((res) => {\n if (!res.ok) throw new Error(`Request failed: ${res.status} ${res.statusText}`)\n return res.json()\n })\n\n/**\n * useRequest\n *\n * A deduplication-first data fetching hook.\n * Multiple components requesting the same key at the same time\n * will share a single in-flight request — not fire multiple.\n *\n * All caching is in-memory only (JS RAM). Nothing is written\n * to localStorage, sessionStorage, or any browser storage.\n *\n * @example\n * // All three components share ONE network request\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n */\nexport function useRequest<T = unknown>(\n key: string | null,\n options: UseRequestOptions<T> = {}\n): UseRequestReturn<T> {\n const {\n fetcher = defaultFetcher as (key: string) => Promise<T>,\n cacheTime = 30_000,\n dedupe = true,\n manual = false,\n onSuccess,\n onError,\n onStatusChange,\n } = options\n\n const [data, setData] = useState<T | undefined>(() => {\n if (!key) return undefined\n return getCached<T>(key, cacheTime) ?? undefined\n })\n const [status, setStatus] = useState<RequestStatus>(() => {\n if (!key) return \"idle\"\n const cached = getCached<T>(key, cacheTime)\n return cached !== null ? \"success\" : \"idle\"\n })\n const [error, setError] = useState<unknown>(undefined)\n\n const mountedRef = useRef(true)\n const onSuccessRef = useRef(onSuccess)\n const onErrorRef = useRef(onError)\n const onStatusChangeRef = useRef(onStatusChange)\n\n // Keep callback refs fresh without causing re-runs\n useEffect(() => { onSuccessRef.current = onSuccess }, [onSuccess])\n useEffect(() => { onErrorRef.current = onError }, [onError])\n useEffect(() => { onStatusChangeRef.current = onStatusChange }, [onStatusChange])\n\n useEffect(() => {\n mountedRef.current = true\n return () => { mountedRef.current = false }\n }, [])\n\n const updateStatus = useCallback((next: RequestStatus) => {\n if (!mountedRef.current) return\n setStatus(next)\n onStatusChangeRef.current?.(next)\n }, [])\n\n const execute = useCallback(\n async (forceRefresh = false): Promise<void> => {\n if (!key) return\n\n // Check cache first (unless force refreshing)\n if (!forceRefresh) {\n const cached = getCached<T>(key, cacheTime)\n if (cached !== null) {\n if (mountedRef.current) {\n setData(cached)\n updateStatus(\"success\")\n }\n return\n }\n } else {\n clearCached(key)\n }\n\n // Check for an in-flight request for this key\n if (dedupe) {\n const existing = getInFlight<T>(key)\n if (existing) {\n updateStatus(\"loading\")\n try {\n const result = await existing\n if (!mountedRef.current) return\n setData(result)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n return\n }\n }\n\n // No cache, no in-flight — fire a new request\n updateStatus(\"loading\")\n\n const promise = fetcher(key)\n\n if (dedupe) {\n setInFlight(key, promise)\n }\n\n try {\n const result = await promise\n setCached(key, result)\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setData(result)\n setError(undefined)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n },\n [key, cacheTime, dedupe, fetcher, updateStatus]\n )\n\n // Auto-fetch on mount unless manual mode\n useEffect(() => {\n if (!key || manual) return\n execute()\n }, [key, manual, execute])\n\n const refetch = useCallback(async () => {\n await execute(true)\n }, [execute])\n\n const clear = useCallback(() => {\n if (!key) return\n clearCached(key)\n setData(undefined)\n setError(undefined)\n updateStatus(\"idle\")\n }, [key, updateStatus])\n\n const is = useCallback(\n (s: RequestStatus) => status === s,\n [status]\n )\n\n return {\n data,\n status,\n error,\n isLoading: status === \"loading\",\n isSuccess: status === \"success\",\n isError: status === \"error\",\n is,\n refetch,\n clear,\n }\n}","import type { CacheEntry, InFlightEntry } from \"./types\"\n\n/**\n * Global in-memory cache — lives in JS RAM only.\n * Never touches localStorage, sessionStorage, or any browser storage.\n * Cleared automatically when the page refreshes or tab closes.\n */\nconst cache = new Map<string, CacheEntry<unknown>>()\n\n/**\n * In-flight registry — tracks requests currently in progress.\n * If a request for the same key is already in flight,\n * new subscribers attach to the existing Promise instead of firing a new request.\n */\nconst inFlight = new Map<string, InFlightEntry<unknown>>()\n\nexport function getCached<T>(key: string, cacheTime: number): T | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined\n if (!entry) return null\n if (cacheTime === 0) return null\n const isStale = Date.now() - entry.timestamp > cacheTime\n if (isStale) {\n cache.delete(key)\n return null\n }\n return entry.data\n}\n\nexport function setCached<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() })\n}\n\nexport function clearCached(key: string): void {\n cache.delete(key)\n}\n\nexport function getInFlight<T>(key: string): Promise<T> | null {\n const entry = inFlight.get(key) as InFlightEntry<T> | undefined\n if (!entry) return null\n entry.subscribers++\n return entry.promise\n}\n\nexport function setInFlight<T>(key: string, promise: Promise<T>): void {\n inFlight.set(key, { promise: promise as Promise<unknown>, subscribers: 1 })\n}\n\nexport function clearInFlight(key: string): void {\n inFlight.delete(key)\n}\n\nexport function clearAll(): void {\n cache.clear()\n inFlight.clear()\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/useRequest.ts","../src/store.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef } from \"react\"\nimport {\n getCached,\n setCached,\n clearCached,\n getInFlight,\n setInFlight,\n clearInFlight,\n} from \"./store\"\nimport type {\n RequestStatus,\n UseRequestOptions,\n UseRequestReturn,\n} from \"./types\"\n\nconst defaultFetcher = (key: string) =>\n fetch(key).then((res) => {\n if (!res.ok) throw new Error(`Request failed: ${res.status} ${res.statusText}`)\n return res.json()\n })\n\n/**\n * useRequest\n *\n * A deduplication-first data fetching hook.\n * Multiple components requesting the same key at the same time\n * will share a single in-flight request — not fire multiple.\n *\n * All caching is in-memory only (JS RAM). Nothing is written\n * to localStorage, sessionStorage, or any browser storage.\n *\n * @example\n * // All three components share ONE network request\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n * const { data } = useRequest(\"/api/user\")\n */\nexport function useRequest<T = unknown>(\n key: string | null,\n options: UseRequestOptions<T> = {}\n): UseRequestReturn<T> {\n const {\n fetcher = defaultFetcher as (key: string) => Promise<T>,\n cacheTime = 30_000,\n dedupe = true,\n manual = false,\n onSuccess,\n onError,\n onStatusChange,\n } = options\n\n const [data, setData] = useState<T | undefined>(() => {\n if (!key) return undefined\n return getCached<T>(key, cacheTime) ?? undefined\n })\n const [status, setStatus] = useState<RequestStatus>(() => {\n if (!key) return \"idle\"\n const cached = getCached<T>(key, cacheTime)\n return cached !== null ? \"success\" : \"idle\"\n })\n const [error, setError] = useState<unknown>(undefined)\n\n const mountedRef = useRef(true)\n const onSuccessRef = useRef(onSuccess)\n const onErrorRef = useRef(onError)\n const onStatusChangeRef = useRef(onStatusChange)\n\n // Keep callback refs fresh without causing re-runs\n useEffect(() => { onSuccessRef.current = onSuccess }, [onSuccess])\n useEffect(() => { onErrorRef.current = onError }, [onError])\n useEffect(() => { onStatusChangeRef.current = onStatusChange }, [onStatusChange])\n\n useEffect(() => {\n mountedRef.current = true\n return () => { mountedRef.current = false }\n }, [])\n\n const updateStatus = useCallback((next: RequestStatus) => {\n if (!mountedRef.current) return\n setStatus(next)\n onStatusChangeRef.current?.(next)\n }, [])\n\n const execute = useCallback(\n async (forceRefresh = false): Promise<void> => {\n if (!key) return\n\n // Check cache first (unless force refreshing)\n if (!forceRefresh) {\n const cached = getCached<T>(key, cacheTime)\n if (cached !== null) {\n if (mountedRef.current) {\n setData(cached)\n updateStatus(\"success\")\n }\n return\n }\n } else {\n clearCached(key)\n }\n\n // Check for an in-flight request for this key\n if (dedupe) {\n const existing = getInFlight<T>(key)\n if (existing) {\n updateStatus(\"loading\")\n try {\n const result = await existing\n if (!mountedRef.current) return\n setData(result)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n return\n }\n }\n\n // No cache, no in-flight — fire a new request\n updateStatus(\"loading\")\n\n const promise = fetcher(key)\n\n if (dedupe) {\n setInFlight(key, promise)\n }\n\n try {\n const result = await promise\n setCached(key, result)\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setData(result)\n setError(undefined)\n updateStatus(\"success\")\n onSuccessRef.current?.(result)\n } catch (err) {\n clearInFlight(key)\n\n if (!mountedRef.current) return\n setError(err)\n updateStatus(\"error\")\n onErrorRef.current?.(err)\n }\n },\n [key, cacheTime, dedupe, fetcher, updateStatus]\n )\n\n // Auto-fetch on mount unless manual mode\n useEffect(() => {\n if (!key || manual) return\n execute()\n }, [key, manual, execute])\n\n const refetch = useCallback(async () => {\n await execute(true)\n }, [execute])\n\n const clear = useCallback(() => {\n if (!key) return\n clearCached(key)\n setData(undefined)\n setError(undefined)\n updateStatus(\"idle\")\n }, [key, updateStatus])\n\n const is = useCallback(\n (s: RequestStatus) => status === s,\n [status]\n )\n\n return {\n data,\n status,\n error,\n isLoading: status === \"loading\",\n isSuccess: status === \"success\",\n isError: status === \"error\",\n is,\n refetch,\n clear,\n }\n}","import type { CacheEntry, InFlightEntry } from \"./types\"\n\n/**\n * Global in-memory cache — lives in JS RAM only.\n * Never touches localStorage, sessionStorage, or any browser storage.\n * Cleared automatically when the page refreshes or tab closes.\n */\nconst cache = new Map<string, CacheEntry<unknown>>()\n\n/**\n * In-flight registry — tracks requests currently in progress.\n * If a request for the same key is already in flight,\n * new subscribers attach to the existing Promise instead of firing a new request.\n */\nconst inFlight = new Map<string, InFlightEntry<unknown>>()\n\nexport function getCached<T>(key: string, cacheTime: number): T | null {\n const entry = cache.get(key) as CacheEntry<T> | undefined\n if (!entry) return null\n if (cacheTime === 0) return null\n const isStale = Date.now() - entry.timestamp > cacheTime\n if (isStale) {\n cache.delete(key)\n return null\n }\n return entry.data\n}\n\nexport function setCached<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() })\n}\n\nexport function clearCached(key: string): void {\n cache.delete(key)\n}\n\nexport function getInFlight<T>(key: string): Promise<T> | null {\n const entry = inFlight.get(key) as InFlightEntry<T> | undefined\n if (!entry) return null\n entry.subscribers++\n return entry.promise\n}\n\nexport function setInFlight<T>(key: string, promise: Promise<T>): void {\n inFlight.set(key, { promise: promise as Promise<unknown>, subscribers: 1 })\n}\n\nexport function clearInFlight(key: string): void {\n inFlight.delete(key)\n}\n\nexport function clearAll(): void {\n cache.clear()\n inFlight.clear()\n}"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hookraft/userequest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Deduplication-first data fetching hook for React. One request fires no matter how many components ask for the same data at the same time.",
|
|
5
5
|
"author": "virus",
|
|
6
6
|
"license": "MIT",
|