Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refresh() is not forcing API call and the cached result is returned #68

Open
m-anwr opened this issue Mar 22, 2024 · 1 comment
Open

Comments

@m-anwr
Copy link

m-anwr commented Mar 22, 2024

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:  npm@9.5.1
- Builder:          -
- User Config:      ssr, runtimeConfig, devtools, css, modules, vue, imports, apiParty
- Runtime Modules:  @nuxtjs/tailwindcss@6.11.4, @vueuse/nuxt@10.9.0, @pinia/nuxt@0.4.11, nuxt-icon@0.4.2, nuxt-api-party@1.1.1
- 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

@m-anwr m-anwr changed the title refresh() is forcing API call and the cached result is returned refresh() is not forcing API call and the cached result is returned Mar 22, 2024
@killjoy1221
Copy link
Contributor

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;
      }
    },
  });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants