Skip to content

Commit 0ee2f46

Browse files
committed
test: Add integration tests for form submission, file upload, CRUD operations, and optimistic updates
1 parent abfa0af commit 0ee2f46

File tree

3 files changed

+718
-18
lines changed

3 files changed

+718
-18
lines changed

src/react/cache-ref.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ export const INFINITE_CACHE_TIME = -1;
1919
const refs = new Map<string, number>();
2020

2121
export const incrementRef = (key: string | null) => {
22-
if (!key) {
23-
return;
22+
if (key) {
23+
refs.set(key, (refs.get(key) || 0) + 1);
2424
}
25-
26-
refs.set(key, (refs.get(key) || 0) + 1);
2725
};
2826

2927
export const decrementRef = (

src/react/index.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { useEffect, useCallback, useSyncExternalStore, useMemo } from 'react';
1+
import {
2+
useEffect,
3+
useCallback,
4+
useSyncExternalStore,
5+
useMemo,
6+
useRef,
7+
} from 'react';
28
import {
39
fetchf,
410
subscribe,
@@ -29,6 +35,11 @@ const DEFAULT_RESULT = {
2935
config: {},
3036
headers: {},
3137
};
38+
const DEFAULT_REF = [null, {}, null] as [
39+
string | null,
40+
RequestConfig,
41+
string | null,
42+
];
3243

3344
/**
3445
* High-performance React hook for fetching data with caching, deduplication, revalidation etc.
@@ -106,6 +117,9 @@ export function useFetcher<
106117
const dedupeTime = config.dedupeTime ?? DEFAULT_DEDUPE_TIME_MS;
107118
const cacheTime = config.cacheTime || INFINITE_CACHE_TIME;
108119

120+
const currentValuesRef = useRef(DEFAULT_REF);
121+
currentValuesRef.current = [url, config, cacheKey];
122+
109123
const shouldTriggerOnMount = useMemo(
110124
() => (config.immediate === undefined ? true : config.immediate),
111125
[config.immediate],
@@ -168,16 +182,18 @@ export function useFetcher<
168182

169183
const refetch = useCallback(
170184
async (forceRefresh = true) => {
171-
// Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.
172-
const shouldRefresh = !!forceRefresh;
185+
const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;
173186

174-
if (!url) {
187+
if (!currUrl) {
175188
return Promise.resolve(null);
176189
}
177190

191+
// Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.
192+
const shouldRefresh = !!forceRefresh;
193+
178194
// Fast path: check cache first if not forcing refresh
179-
if (!shouldRefresh && cacheKey) {
180-
const cached = getCachedResponse(cacheKey, cacheTime, config);
195+
if (!shouldRefresh && currCacheKey) {
196+
const cached = getCachedResponse(currCacheKey, cacheTime, currConfig);
181197

182198
if (cached) {
183199
return Promise.resolve(cached);
@@ -186,11 +202,11 @@ export function useFetcher<
186202

187203
// When manual refetch is triggered, we want to ensure that the cache is busted
188204
// This can be disabled by passing `refetch(false)`
189-
const cacheBuster = shouldRefresh ? () => true : config.cacheBuster;
205+
const cacheBuster = shouldRefresh ? () => true : currConfig.cacheBuster;
190206

191-
return await fetchf(url, {
192-
...config,
193-
cacheKey,
207+
return await fetchf(currUrl, {
208+
...currConfig,
209+
cacheKey: currCacheKey,
194210
dedupeTime,
195211
cacheTime,
196212
cacheBuster,
@@ -199,14 +215,14 @@ export function useFetcher<
199215
cacheErrors: true,
200216
});
201217
},
202-
[url, cacheKey, cacheTime, dedupeTime],
218+
[cacheTime, dedupeTime],
203219
);
204220

205221
useEffect(() => {
206222
// Load the initial data if not already cached and not currently fetching
207223
if (
208-
url &&
209224
shouldTriggerOnMount &&
225+
currentValuesRef.current[0] &&
210226
!state.data &&
211227
!state.error &&
212228
!state.isFetching
@@ -223,9 +239,14 @@ export function useFetcher<
223239
incrementRef(cacheKey);
224240

225241
return () => {
226-
decrementRef(cacheKey, cacheTime, dedupeTime, url);
242+
decrementRef(
243+
cacheKey,
244+
cacheTime,
245+
dedupeTime,
246+
currentValuesRef.current[0],
247+
);
227248
};
228-
}, [url, shouldTriggerOnMount, refetch, cacheKey, cacheTime]);
249+
}, [shouldTriggerOnMount, cacheKey, cacheTime]);
229250

230251
const mutate = useCallback<
231252
UseFetcherResult<

0 commit comments

Comments
 (0)