Skip to content

Commit

Permalink
feat: implement fallback option
Browse files Browse the repository at this point in the history
  • Loading branch information
edumudu committed Aug 11, 2022
1 parent 4619199 commit 0402100
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 8 deletions.
3 changes: 2 additions & 1 deletion docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)
- `revalidateOnReconnect = true` - Automatically revalidate when the browser regains a network connection
- `revalidateIfStale = true` - Automatically revalidate if there is stale data
- `dedupingInterval = 2000` - dedupe requests with the same key in this time span in milliseconds
- `fallbackData` - initial data to be returned (note: This is per-composable, but also be passed in global config)
- `fallback` - a key-value object of multiple fallback data
- `fallbackData` - initial data to be returned (this has priority over `fallback` option)
- `onSuccess(data, key, config)` - callback function when a request finishes successfully
- `onError(err, key, config)` - callback function when a request returns an error
4 changes: 3 additions & 1 deletion lib/composables/swr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,21 @@ export const useSWR = <Data = any, Error = any>(
revalidateOnReconnect,
revalidateIfStale,
dedupingInterval,
fallback,
fallbackData,
onSuccess,
onError,
} = mergedConfig;

const { key, args: fetcherArgs } = toRefs(toReactive(computed(() => serializeKey(_key))));
const fallbackValue = fallbackData === undefined ? fallback?.[key.value] : fallbackData;

const valueInCache = computed(() => cacheProvider.get(key.value));
const hasCachedValue = computed(() => !!valueInCache.value);

const error = valueInCache.value ? toRef(valueInCache.value, 'error') : ref<Error>();
const isValidating = valueInCache.value ? toRef(valueInCache.value, 'isValidating') : ref(true);
const data = valueInCache.value ? toRef(valueInCache.value, 'data') : ref(fallbackData);
const data = valueInCache.value ? toRef(valueInCache.value, 'data') : ref(fallbackValue);
const fetchedIn = valueInCache.value ? toRef(valueInCache.value, 'fetchedIn') : ref(new Date());

const fetchData = async () => {
Expand Down
71 changes: 66 additions & 5 deletions lib/composables/swr/swr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,15 +532,20 @@ describe('useSWR', () => {
);
});

it('should return fallbackData as initial value', () => {
const fallbackData = 'fallback';

it.each([
'fallback',
'Lorem ispum dolor sit amet',
100,
['item1', 'item2'],
{ a: 1, b: '' },
null,
])('should return fallbackData "%s" as initial value', (fallbackData) => {
const { data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider }),
() => useSWR(defaultKey, defaultFetcher, { fallbackData }),
);

expect(data.value).toBe(fallbackData);
expect(data.value).toEqual(fallbackData);
});

it('should return global fallbackData as initial value', () => {
Expand All @@ -554,7 +559,7 @@ describe('useSWR', () => {
expect(data.value).toBe(fallbackData);
});

it('should return stale data fallbackData and stale data are present', async () => {
it('should return stale data if fallbackData and stale data are present', async () => {
const fallbackData = 'fallback';
const cahedData = 'cached value';

Expand All @@ -568,4 +573,60 @@ describe('useSWR', () => {
await flushPromises();
expect(data.value).toBe(cahedData);
});

it.each([
'fallback',
'Lorem ispum dolor sit amet',
100,
['item1', 'item2'],
{ a: 1, b: '' },
null,
])('should return data "%s" in fallback as initial value', (fallbackData) => {
const fallback = { [defaultKey]: fallbackData };

const { data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider }),
() => useSWR(defaultKey, defaultFetcher, { fallback }),
);

expect(data.value).toEqual(fallbackData);
});

it('should return data in global fallback as initial value', () => {
const fallback = { [defaultKey]: 'fallback' };

const { data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider, fallback }),
() => useSWR(defaultKey, defaultFetcher),
);

expect(data.value).toBe('fallback');
});

it('should return stale data if fallback and stale data are present', async () => {
const fallback = { [defaultKey]: 'fallback' };
const cahedData = 'cached value';

setDataToCache(defaultKey, { data: cahedData });

const { data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider, fallback }),
() => useSWR(defaultKey, defaultFetcher),
);

await flushPromises();
expect(data.value).toBe(cahedData);
});

it('should give priority to fallbackData over fallback as initial value', () => {
const fallback = { [defaultKey]: 'fallback' };
const fallbackData = 'fallbackData';

const { data } = useInjectedSetup(
() => configureGlobalSWR({ cacheProvider, fallback, fallbackData }),
() => useSWR(defaultKey, defaultFetcher),
);

expect(data.value).toBe(fallbackData);
});
});
7 changes: 6 additions & 1 deletion lib/types/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ export type SWRConfig<Data = any, Err = any> = {
dedupingInterval: number;

/**
* initial data to be returned (note: ***This is per-composable***)
* a key-value object of multiple fallback data
*/
fallback?: Record<string, any>;

/**
* initial data to be returned
*/
fallbackData?: Data;

Expand Down

0 comments on commit 0402100

Please sign in to comment.