nuxt-api-party
nuxt-api-party copied to clipboard
`refresh()` is not forcing API call and the cached result is returned
Environment
Working directory: /home/anwr/toys/darts_arena/frontend 4:10:00 PM
Nuxt project info: 4:10:00 PM
------------------------------
- Operating System: Linux
- Node Version: v18.16.0
- Nuxt Version: 3.11.1
- CLI Version: 3.11.1
- Nitro Version: 2.9.4
- Package Manager: [email protected]
- Builder: -
- User Config: ssr, runtimeConfig, devtools, css, modules, vue, imports, apiParty
- Runtime Modules: @nuxtjs/[email protected], @vueuse/[email protected], @pinia/[email protected], [email protected], [email protected]
- Build Modules: -
------------------------------
Reproduction
<template>
<main class="mx-auto max-w-xl">
<div v-if="pending" class="w-full py-4 flex justify-center items-center">
<span class="px-2">Loading Posts</span>
<span class="loading loading-spin"></span>
</div>
<button @click="refresh">Refresh</button>
<PostList :posts="data" />
</main>
</div>
</template>
<script setup>
definePageMeta({
layout: "main",
});
const { data, pending, refresh } = await useApiData("posts");
</script>
Describe the bug
When the Refresh button is clicked, the API is not called and the cached result is returned. Is that the expected behavior? I can't find any reference for that in the docs.
A workaround would be to use a custom cache key and change it if I wanted to refresh the content. otherwise, I have to set the cache to false
Additional context
No response
Logs
No response
I've also experienced this and have written a workaround. Just pass your AsyncData object to useUncachedData(). Using a custom key is required to ensure consistency.
import type { AsyncData } from "#app";
const CACHE_KEY_PREFIX = "$apiParty";
type Keys = MaybeRefOrGetter<string | string[]> | MaybeRefOrGetter<string>[];
/**
* Modifies an `AsyncData` object's `refresh` method so it ignores the cache
* when called.
*
* The `key` parameter must be the same as passed to the `key` option in
* `useApiData()`.
*
* @param keyRef The cache key used in `useApiData()`
* @param data The AsyncData result from `useApiData()`
*
* @example
* ```ts
* const { data, refresh } = useUncachedData(
* "myKey",
* useApiData("some/path", {
* key: "myKey"
* }),
* )
* ```
*/
export function useUncachedData<Data, Error>(keyRef: Keys, data: AsyncData<Data, Error>) {
const keys = computed(() => {
const keys = toValue(keyRef);
if (Array.isArray(keys)) {
return keys.map(useCacheRef);
}
return [useCacheRef(keys)];
});
// make refresh ignore the cache
const { refresh } = data;
const refreshInvalidate: typeof refresh = async (opts) => {
// invalidate the cache
for (const key of keys.value) {
key.value = undefined;
}
return await refresh(opts);
};
data.refresh = refreshInvalidate;
// awaiting gets the original asyncdata object, which is separate from the Promise
data.then((asyncData) => {
asyncData.refresh = refreshInvalidate;
});
return data;
}
export function useCacheRef<T = unknown>(key: MaybeRefOrGetter<string>) {
const nuxt = useNuxtApp();
return computed<T | undefined>({
get: () => nuxt.payload.data[CACHE_KEY_PREFIX + toValue(key)],
set: (value) => {
if (value === undefined) {
delete nuxt.payload.data[CACHE_KEY_PREFIX + toValue(key)];
} else {
nuxt.payload.data[CACHE_KEY_PREFIX + toValue(key)] = value;
}
},
});
}
With the latest Nuxt versions, you can use the clear function provided in the async data object to clear the fetched data and refetch afterwards:
const { data, refresh, clear } = await useApiData("posts")
async function invalidateAndRefresh() {
clear()
await refresh()
}