TanStack / query

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
https://tanstack.com/query
MIT License
42.54k stars 2.91k forks source link

Vue query not working with Nuxt 3 using enabled option and suspense #4924

Closed lucas-santosP closed 1 year ago

lucas-santosP commented 1 year ago

Describe the bug

When using useQuery in Nuxt 3 with enabled equals to false and with await suspense() the page simply does not load. It seems like the suspense call stays on loading eternally. It might be something related to the enabled and status change in TanStack query 4.x version as described here (idle state removed). As I understood when the enabled value is false the query status will remain equals to "loading".

Your minimal, reproducible example

https://github.com/lucas-santosP/example-nuxt-vue-query

Steps to reproduce

To reproduce the error you simply need a useQuery hook with enabled=false and await suspense call:

const { data, suspense, isLoading, status } = useQuery({
  queryKey: ["test"],
  queryFn: fetcher,
  enabled: false,
});
await suspense();

My reproducible example does that by default, so by running the dev mode with yarn dev you'll be able to see the error (the page will stay on loading forever). To fix it you can change the initial value of the enabled variable to true or remove the await suspense call.

Expected behavior

When using the enabled option is expected that the query will not be executed so the await suspense should not block the page loading.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

nuxi info:

TanStack Query version

v4.24.4

TypeScript version

No response

Additional context

No response

DamianOsipiuk commented 1 year ago

Hi, Your observations are correct. If you use suspense with enabled: false component will suspend until you change the flag to true. This is useful if you want to suspend the component until specific condition is met.

If your enabled flag is set to false, why would you call suspense in the first place? In the situation you are talking about it would be treated as a noop, but i'm not sure if this is the correct behavior.

Could explain a little bit more why would you want to use suspense with enabled:false?

lucas-santosP commented 1 year ago

The problem that expires me to open this issue was: I'm trying to do a searching page where the input value is synced with a URL query param. The initial fetch is made based on the query param value, so the enabled option depends if the URL query param exists.

I'm getting the query param value from Vue router useRoute and using watch to track and sync a ref value with the URL query param.

useUrlSearchParam.ts

export function useUrlSearchParam(key: string) { 
   const route = useRoute(); 
   const param = ref(""); 

   const querySearch = route.query[key]; 
   if (typeof querySearch === "string") { 
     param.value = querySearch; 
   } 

   watch( 
     () => param.value, 
     () => { 
      if (!param.value) { 
         return; 
       }

       navigateTo({ 
         path: route.path, 
         query: { ...route.query, [key]: param.value ? param.value : undefined }, 
       }); 
     } 
   ); 

   return param; 
 }

pages/index.vue script setup:

const searchParam = useUrlSearchParam("search"); 

const queryEnabled = computed(() => !!searchParam.value); 

const = { data, suspense } useQuery({ 
queryKey: ["list-search", searchParam],
queryFn: async () => {
const response = await apiClient.searchData({ queries: { q: searchParam.value } }); 
return response.data; 
}, 
enabled: queryEnabled,
});

await suspense();

I couldn't make this work using suspense. Because even with a URL query param the component rendering is blocked.

The behavior I was expecting doing that:

DamianOsipiuk commented 1 year ago

Is there anything preventing you from doing the following?

if (queryEnabled.value) {
  await suspense();
}

It should work the way you want.

lucas-santosP commented 1 year ago

Well thanks that worked. But still, the behavior of suspense in relation to the enabled option seems weird in my opinion.

Since enabled false means that it's a disabled query and so the fetchStatus will be idle, because of that, skipping the disabled query even in the suspense call was the first behavior that comes to my mind... But as you said the current implementation can be a useful behavior in some use cases too.

* If you want to complement anything about what I said I'm open to hear, otherwise we can close this issue. 🫡

DamianOsipiuk commented 1 year ago

I found the ticket in old repo particularly about the behavior you expect. https://github.com/DamianOsipiuk/vue-query/issues/229

Since current implementation handles both cases, i will leave it as-is.