Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b3da407

Browse files
authoredJul 26, 2023
Merge pull request #68 from BetterTyped/fix/dynamic-revalidate
fix: 🐛 Refreshing and revalidation fixes
2 parents a529469 + 05136cd commit b3da407

File tree

5 files changed

+77
-7
lines changed

5 files changed

+77
-7
lines changed
 

‎packages/react/__tests__/features/use-fetch/use-fetch.refresh.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,27 @@ describe("useFetch [ Refreshing ]", () => {
8282
it("should postpone refresh when dependencies change during countdown", async () => {
8383
// TODO
8484
});
85+
it("should stop refreshing when value is changing from true to false", async () => {
86+
const spy = jest.fn();
87+
createRequestInterceptor(request);
88+
const { result, rerender } = renderUseFetch(request, hookOptions);
89+
90+
act(() => {
91+
result.current.onRequestStart(spy);
92+
});
93+
94+
await waitForRender();
95+
expect(spy).toBeCalledTimes(1);
96+
await waitForRender(hookOptions.refreshTime * 1.5);
97+
98+
expect(spy).toBeCalledTimes(2);
99+
100+
act(() => {
101+
rerender({ refresh: false });
102+
});
103+
104+
await waitForRender(hookOptions.refreshTime * 1.5);
105+
106+
expect(spy).toBeCalledTimes(2);
107+
});
85108
});

‎packages/react/__tests__/features/use-fetch/use-fetch.revalidate.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,44 @@ describe("useFetch [ refetch ]", () => {
180180
await testSuccessState(mock, responseTwo);
181181
});
182182
});
183+
it("should not refetch while toggling query", async () => {
184+
const spy = jest.fn();
185+
186+
const revalidateRequest = createRequest({ endpoint: "123-revalidate" });
187+
const revalidateMock = createRequestInterceptor(revalidateRequest, { fixture: { something: 123 } });
188+
189+
// First request
190+
const response = renderUseFetch(request, { revalidate: false });
191+
192+
response.result.current.onFinished(() => {
193+
spy();
194+
});
195+
196+
await testSuccessState(mock, response);
197+
expect(spy).toBeCalledTimes(1);
198+
199+
act(() => {
200+
// Second request
201+
response.rerender({ request: revalidateRequest, revalidate: false });
202+
});
203+
204+
await testSuccessState(revalidateMock, response);
205+
expect(spy).toBeCalledTimes(2);
206+
207+
// Check revalidation
208+
209+
act(() => {
210+
// Third request
211+
response.rerender({ request, revalidate: false });
212+
});
213+
await testSuccessState(mock, response);
214+
215+
act(() => {
216+
// Fourth request
217+
response.rerender({ request: revalidateRequest, revalidate: false });
218+
});
219+
220+
await testSuccessState(revalidateMock, response);
221+
expect(spy).toBeCalledTimes(2);
222+
});
183223
});

‎packages/react/src/helpers/use-tracked-state/use-tracked-state.hooks.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ export const useTrackedState = <T extends RequestInstance>({
4747

4848
const getStaleStatus = (): boolean => {
4949
const cacheData = cache.get(cacheKey);
50-
51-
return isStaleCacheData(cacheTime, cacheData?.timestamp || state.current.timestamp);
50+
return !cacheData || isStaleCacheData(cacheTime, cacheData?.timestamp);
5251
};
5352

5453
// ******************
@@ -83,10 +82,14 @@ export const useTrackedState = <T extends RequestInstance>({
8382
const shouldLoadInitialCache = !hasState && !!state.current.data;
8483
const shouldRemovePreviousData = hasState && !state.current.data;
8584

86-
if (shouldLoadInitialCache || shouldRemovePreviousData) {
85+
if (newState.data || shouldLoadInitialCache || shouldRemovePreviousData) {
8786
// Don't update the state when we are fetching data for new cacheKey
8887
// So on paginated page we will have previous page access until the new one will be fetched
88+
// However: When we have some cached data, we can use it right away
8989
state.current = newState;
90+
if (state.current) {
91+
renderKeyTrigger(["data"]);
92+
}
9093
}
9194
},
9295
[cacheKey, queueKey],

‎packages/react/src/hooks/use-fetch/use-fetch.hooks.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ export const useFetch = <RequestType extends RequestInstance>(
9999
// ******************
100100

101101
function handleRefresh() {
102-
if (!refresh) return;
102+
if (!refresh) {
103+
refreshDebounce.reset();
104+
return;
105+
}
103106

104107
refreshDebounce.debounce(() => {
105108
const isBlurred = !appManager.isFocused;
@@ -159,12 +162,13 @@ export const useFetch = <RequestType extends RequestInstance>(
159162
};
160163

161164
const updateFetchData = () => {
165+
const hasStaleData = getStaleStatus();
166+
const shouldUpdate = !revalidate ? hasStaleData : true;
162167
/**
163168
* This is a hack to avoid double rendering in React 18
164169
* It renders initial mount event and allow us to consume only hook updates
165170
*/
166-
167-
if (!ignoreReact18DoubleRender.current) {
171+
if (!ignoreReact18DoubleRender.current && shouldUpdate) {
168172
/**
169173
* While debouncing we need to make sure that first request is not debounced when the cache is not available
170174
* This way it will not wait for debouncing but fetch data right away

‎packages/react/src/hooks/use-submit/use-submit.hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const useSubmit = <RequestType extends RequestInstance>(
4040
...options,
4141
}),
4242
// eslint-disable-next-line react-hooks/exhaustive-deps
43-
[JSON.stringify(globalConfig.useSubmitConfig), JSON.stringify(options)],
43+
[globalConfig.useSubmitConfig, JSON.stringify(options), options.deepCompare],
4444
);
4545
const { disabled, dependencyTracking, initialData, bounce, bounceType, bounceTime, deepCompare } = mergedOptions;
4646

0 commit comments

Comments
 (0)
Please sign in to comment.