Skip to content

Commit

Permalink
fix: skip dedup when call mutate
Browse files Browse the repository at this point in the history
  • Loading branch information
edumudu committed Sep 8, 2022
1 parent a5b8b63 commit 7481166
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 79 deletions.
13 changes: 10 additions & 3 deletions lib/composables/swr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createUnrefFn, toReactive, useEventListener, useIntervalFn } from '@vue
import type {
MaybeRef,
OmitFirstArrayIndex,
RevalidatorOpts,
SWRComposableConfig,
SWRConfig,
SWRFetcher,
Expand Down Expand Up @@ -88,11 +89,16 @@ export const useSWR = <Data = any, Error = any>(
const fetchedIn = useCachedRef(valueInCache.value?.fetchedIn ?? new Date(), { cache: cacheProvider, stateKey: 'fetchedIn', key });
/* eslint-enable */

const fetchData = async () => {
const fetchData = async (opts: RevalidatorOpts = { dedup: true }) => {
const timestampToDedupExpire = (fetchedIn.value?.getTime() || 0) + dedupingInterval;
const hasNotExpired = timestampToDedupExpire > Date.now();

if (hasCachedValue.value && (hasNotExpired || (isValidating.value && dedupingInterval !== 0)))
// Dedup requets
if (
opts.dedup &&
hasCachedValue.value &&
(hasNotExpired || (isValidating.value && dedupingInterval !== 0))
)
return;

isValidating.value = true;
Expand Down Expand Up @@ -140,7 +146,8 @@ export const useSWR = <Data = any, Error = any>(
return;
}

await fetchData();
// Skip dedup when trigger by mutate
await fetchData({ dedup: false });
};

const onKeyChange = (newKey: string, oldKey?: string) => {
Expand Down
59 changes: 51 additions & 8 deletions lib/composables/swr/swr-mutate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const setTimeoutPromise = (ms: number, resolveTo: unknown) =>

const useSWRWrapped: typeof useSWR = (...params) => {
return useInjectedSetup(
() => configureGlobalSWR({ cacheProvider, dedupingInterval: 0 }),
() => configureGlobalSWR({ cacheProvider }),
() => useSWR(...params),
);
};
Expand All @@ -40,18 +40,23 @@ describe('useSWR - mutate', () => {
vi.useRealTimers();
});

it('should change local data variable value when mutate resolves', async () => {
it('should change local data variable value when binded mutate resolves', async () => {
const { mutate, data } = useSWRWrapped(defaultKey, () => 'FetcherResult');

await nextTick();
expect(data.value).toEqual('FetcherResult');

await mutate(() => 'newValue', { revalidate: false });
await nextTick();
expect(data.value).toEqual('newValue');

await mutate(Promise.resolve('promised value'), { revalidate: false });
expect(data.value).toEqual('promised value');

await mutate(['raw value'], { revalidate: false });
expect(data.value).toEqual(['raw value']);
});

it('should change local data variable value when mutate is called with `optimistcData`', async () => {
it('should change local data variable value when binded mutate is called with `optimistcData`', async () => {
setDataToMockedCache(defaultKey, { data: 'cachedData' });

const { mutate, data } = useInjectedSetup(
Expand All @@ -61,12 +66,15 @@ describe('useSWR - mutate', () => {

expect(data.value).toEqual('cachedData');

mutate(() => setTimeoutPromise(1000, 'newValue'), { optimisticData: 'optimistcData' });
mutate(() => setTimeoutPromise(1000, 'newValue'), {
optimisticData: 'optimistcData',
revalidate: false,
});
await nextTick();
expect(data.value).toEqual('optimistcData');
});

it('should update all hooks with the same key when call mutates', async () => {
it('should update all hooks with the same key when call binded mutate', async () => {
setDataToMockedCache(defaultKey, { data: 'cachedData' });

const { datas, mutate, differentData } = useInjectedSetup(
Expand All @@ -93,7 +101,8 @@ describe('useSWR - mutate', () => {
'cachedData',
]);

await mutate(() => 'mutated value');
await mutate(() => 'mutated value', { revalidate: false });
await nextTick();
expect(datas.map((data) => data.value)).toEqual([
'mutated value',
'mutated value',
Expand All @@ -112,7 +121,7 @@ describe('useSWR - mutate', () => {
() => {
const { mutate: localGlobalMutate } = useSWRConfig();
// eslint-disable-next-line no-plusplus
const swrResult = useSWR(defaultKey, () => value++, { dedupingInterval: 0 });
const swrResult = useSWR(defaultKey, () => value++);

return {
globalMutate: localGlobalMutate,
Expand All @@ -134,4 +143,38 @@ describe('useSWR - mutate', () => {
await nextTick();
expect(data.value).toEqual(2);
});

it('should ignore dedup interval when call binded mutate', async () => {
const fetcher = defaultFetcher;
const { mutate } = useSWRWrapped(defaultKey, fetcher, { dedupingInterval: 50000000 });

await nextTick();
fetcher.mockReset();

await mutate();
expect(fetcher).toHaveBeenCalledTimes(1);

await mutate();
expect(fetcher).toHaveBeenCalledTimes(2);
});

it('should revalidate when call binded mutate', async () => {
const fetcher = defaultFetcher;
const { mutate } = useSWRWrapped(defaultKey, fetcher, { dedupingInterval: 50000000 });

await nextTick();
fetcher.mockReset();

await mutate();
expect(fetcher).toHaveBeenCalledOnce();

await mutate(['new vakye']);
expect(fetcher).toHaveBeenCalledTimes(2);

await mutate(() => 'new vakye');
expect(fetcher).toHaveBeenCalledTimes(3);

await mutate(Promise.resolve('promised value'));
expect(fetcher).toHaveBeenCalledTimes(4);
});
});
67 changes: 0 additions & 67 deletions lib/composables/swr/swr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,73 +277,6 @@ describe('useSWR', () => {
expect(fetcher).not.toHaveBeenCalled();
});

it('should change local data variable value when mutate resolves', async () => {
setDataToMockedCache(defaultKey, { data: 'cachedData' });

const { mutate, data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider }),
() => useSWR(defaultKey, () => 'FetcherResult'),
);

expect(data.value).toEqual('cachedData');
await mutate(() => 'newValue');

expect(data.value).toEqual('newValue');
});

it('should change local data variable value when mutate is called with `optimistcData`', async () => {
setDataToMockedCache(defaultKey, { data: 'cachedData' });

const { mutate, data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider }),
() => useSWR(defaultKey, () => 'FetcherResult'),
);

expect(data.value).toEqual('cachedData');

mutate(() => setTimeoutPromise(1000, 'newValue'), { optimisticData: 'optimistcData' });
await nextTick();
expect(data.value).toEqual('optimistcData');
});

it('should update all hooks with the same key when call mutates', async () => {
setDataToMockedCache(defaultKey, { data: 'cachedData' });

const { datas, mutate, differentData } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider }),
() => {
const { data: data1, mutate: localMutate } = useSWR(defaultKey, defaultFetcher);
const { data: data2 } = useSWR(defaultKey, defaultFetcher);
const { data: data3 } = useSWR(defaultKey, defaultFetcher);
const { data: data4 } = useSWR(defaultKey, defaultFetcher);
const { data: differentData1 } = useSWR('key-2', () => 'should not change');

return {
differentData: differentData1,
datas: [data1, data2, data3, data4],
mutate: localMutate,
};
},
);

expect(datas.map((data) => data.value)).toEqual([
'cachedData',
'cachedData',
'cachedData',
'cachedData',
]);

await mutate(() => 'mutated value');
expect(datas.map((data) => data.value)).toEqual([
'mutated value',
'mutated value',
'mutated value',
'mutated value',
]);

expect(differentData.value).toEqual('should not change');
});

it('should not refresh if refreshInterval = 0', async () => {
const fetcher = vi.fn(defaultFetcher);

Expand Down
4 changes: 4 additions & 0 deletions lib/types/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export type ScopeState = {
revalidateCache: Map<string, Array<() => void | Promise<void>>>; // callbacks to revalidate when key changes
};

export type RevalidatorOpts = {
dedup?: boolean;
};

export type SWRConfig<Data = any, Err = any> = {
/**
* stores the cached values
Expand Down
1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"types": ["vite/client", "vitest/globals"],
"declarationDir": "./dist/types",
"declaration": true,
"declarationMap": true
},
"include": ["lib"]
}

0 comments on commit 7481166

Please sign in to comment.