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

useAsyncQuery can't refresh #496

Open
Saurou opened this issue Mar 23, 2023 · 11 comments
Open

useAsyncQuery can't refresh #496

Saurou opened this issue Mar 23, 2023 · 11 comments
Labels

Comments

@Saurou
Copy link

Saurou commented Mar 23, 2023

Environment

I came across different issues opened about what it looks to be the same problem.

I have not been able to refresh the data of useAsyncQuery in any way.

Describe the bug

useAsyncQuery only seems to work on page refresh / landing.

Expected behaviour

refresh() or watch makes no different (not sure they are even needed on route change).

Reproduction

No response

Additional context

Nuxt 3 documentation does not mention useAsyncQuery: is this actually usable in Nuxt 3?

Logs

No response

@Saurou Saurou added the bug label Mar 23, 2023
@Saurou
Copy link
Author

Saurou commented Mar 24, 2023

Looks like the issue might be related to the token.

After many tries I gave a go to nuxt-graphql-client instead.

While testing I made the api public and everything immediately worked.
When I tried a token to access it, I experienced the same errors on pages navigation.

This time, however, I found a retainToken option in that documentation which, added and set to true, fixed the issue.

Not sure if apollo has a similar thing, I expect it does, though I will probably stick to nuxt-graphql-client at this point.

@guendev
Copy link

guendev commented Apr 30, 2023

In Addition, The result from useAsyncQuery is unable to update automatically with Apollo Cache. I had to write a custom useAsyncQuery. It is still working for me.

type Options<TResult, TVariables> = OptionsParameter<TResult, TVariables> & {
  key?: string
}

export const useAsyncQuery = async <TResult = any, TVariables extends OperationVariables = OperationVariables> (document: DocumentParameter<TResult, TVariables>, variables?: VariablesParameter<TVariables>, options?: Options<TResult, TVariables>) => {
  const { client } = useApolloClient()

  const fn = () => client.query<TResult, TVariables>({
    query: document as DocumentNode,
    variables: variables as TVariables
  }).then((res) => res.data)

  const key = options?.key || hash({ query: print(document as DocumentNode), variables })
  await useAsyncData(key, fn)

  return useQuery(document, variables as TVariables)
}

Basically, I call useAsyncData to write the result to Apollo Cache and return useQuery instead.

@ssyberg
Copy link

ssyberg commented Nov 15, 2023

Also experiencing this issue, I'm kinda blown away this isn't tripping everyone up. Is is just no on is using this package? What are we missing.

@mpgalaxy
Copy link

mpgalaxy commented Dec 1, 2023

Also experiencing this issue, I'm kinda blown away this isn't tripping everyone up. Is is just no on is using this package? What are we missing.

Same here, this is really annoying, in nuxt2 I was refreshing my queries via EventBus after closing a modal, worked perfectly fine. With this version (5.0.0-alpha.10 and before) I can call the refresh function but no refresh is happening.
useAsyncQuery works perfectly fine for fetching queries once in async setup().

@ssyberg
Copy link

ssyberg commented Dec 1, 2023

We ended up doing a bunch of extra work to ensure we're only calling useAsyncQuery server side and useQuery client side. It makes our code brittle and not very DRY but it's the only thing we found could work. I wish I had a better understanding of why useAsyncQuery is not recommended for client side.

@mpgalaxy
Copy link

mpgalaxy commented Dec 4, 2023

UPDATE: @ssyberg : I just found out that reactive queries in options api are working like in nuxt2, you just have to place the apollo object after the setup routine, this is awesome !!! :) With that you can easily do a this.$apollo.queries.myquery.refresh() and everything is perfectly fine, no need for useAsyncQuery, just everything out of the box, like in nuxt2.

export default defineNuxtComponent({
  name: "MyTest",
  async setup(props) {
     .....
  },
  apollo: {
    setting: {
      query: gql`
        query ($name: String!) {
          setting(where: { name: $name }) {
            show
          }
        }
      `,
      variables() {
        return {
          name: "showNameOfSomeone",
        };
      },
      update: (data) => data.setting,
      error() {
        if (process.client) {
          this.$nextTick(() => {
            this.$buefy.toast.open({
              message: this.$t("loading_error"),
              type: "is-danger",
            });
          });
        }
      },
    },
   currentSchemas: {
      query: gql`
      .......
 },
 data() {
    return {
        ......

@rutgerbakker95
Copy link

We ended up doing a bunch of extra work to ensure we're only calling useAsyncQuery server side and useQuery client side. It makes our code brittle and not very DRY but it's the only thing we found could work. I wish I had a better understanding of why useAsyncQuery is not recommended for client side.

@ssyberg Same issue here

@sneakylenny
Copy link

sneakylenny commented Jun 20, 2024

Understanding the Issue with "Refresh"

Discovery Process

While looking into the code and experimenting, I discovered something:
The asynchronous queries are wrapped in Nuxt's useAsyncData, which explains why we get refresh in return instead of vue-apollo's (the underlying package) refetch.
I actually discovered why it doesn't work when playing around with the caching options.

Conclusion: refresh =\= refetch

When executing the refresh method returned by useAsyncQuery it doesn't execute the refetch method from the underlying package. It just executes the function passed to the useAsyncData again. Which results in loading the response from cache if cache is enabled (which is enabled by default).

Solution/workaround

If you want to be able to refresh you'll need to globally disable the cache. Which is a bummer if you'd like to cache. You can still enable cache by setting it true like this: (would love to have this documented)

const { data, refresh } = await useAsyncQuery({
  query,
  variables,
  cache: true // Here
})

Caveat using this solution/workaround

For some reason when cache is globally enabled setting it false does not work due to this line here which could be fixed with this PR

TL:DR

Refresh does not "refetch" when cache is enabled.

@germaniuz
Copy link

@timyourivh thanks for approach, it works! But cache is very important for optimization. Is it possible to fix?

@MilesWuCode
Copy link

Same issue

@LorenzoRottigni
Copy link

LorenzoRottigni commented Oct 20, 2024

Hello there,
I share also my workaround, it is correctly working both for pinia store and component script setup (achieving the same desired behavior of using the official useAsyncData composable):

  async function search(input: SearchInput = searchInput.value): Promise<NormalizedSearchResponse | null> {
    try {
      const { data } = await useAsyncQuery<{ search: SearchResponse }>(
        SEARCH,
        { input } as SearchQueryVariables,
      )
      return data?.value?.search
        ? ({
          ...data?.value?.search,
          items: data?.value?.search?.items?.map((item: SearchResult) => normalizeSearch(item)) || []
        })
        : null
    } catch (err) {
      console.error(err)
      return null
    }
  }

  const searchResult = useAsyncData<NormalizedSearchResponse | null>(
    'products',
    () => search(searchInput.value),
    { watch: [searchInput] }
  )

I tried hard to use the useAsyncQuery composable and i also gave a look to the nuxt-apollo module's core... This is the only way I found to refresh a search graphql request based off the query params.

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

No branches or pull requests

9 participants