useFetch with reactive variables called twice
I have a simple composables for feth the table data. when change the pageIndex it call twice the first one throw error from ns_binding_error and the second one return results.
I want to know why this happend and it call twice ?
and the important thing found: it call the request with old
pagination data and not changed them.8 Replies
Hi @Farshad Fahimi. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
The double call and the issue with old pagination data are known behaviors in Nuxt's
The double call and use of old data are due to how Vue and Nuxt handle reactivity and watchers on objects. To avoid this, batch your updates or use a computed getter that only updates after all relevant properties have changed. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
useFetch when using reactive objects or computed properties as query parameters.
Why does useFetch call twice?
When you use a computed or reactive object in the query option, useFetch automatically watches those dependencies and triggers a refetch when they change. However, if you update multiple properties of a reactive object (like pagination.value.pageIndex and pagination.value.pageSize) in quick succession, the watcher may trigger a fetch for each change, sometimes before all properties are updated. This can result in:
- The first request being sent with the old or partially updated data (e.g., old pageIndex).
- The second request being sent with the new, correct data.
This is due to how Vue's synchronous watchers work: when you mutate a reactive object, each property change can trigger a watcher immediately, before the rest of the object is updated. This is documented as a caveat in the Nuxt and Vue ecosystem, and has been reported as a source of confusion and bugs, especially after Nuxt 3.17.2 and 4.0.0+ where a "flush: sync" watcher is used internally for useFetch and useAsyncData [Github Issue].
The watcher executes straight away on the first change before the rest of the object has been modified (which is indeed exactly what is happening)Why does it call with old pagination data? Because the watcher triggers on the first property change, the fetch is executed with the state of the object at that moment—before all intended changes are applied. For example, if you update
— Github Issue
pagination.value.pageIndex and then pagination.value.pageSize, the fetch may be triggered after the first update, using the old value of pageSize.
How to avoid this?
Workarounds:
1. Batch updates: Instead of mutating properties individually, update the entire object at once. For example:
This reduces the number of watcher triggers.
2. Use a separate watcher: Use a watch on the relevant properties and update a separate ref that is used in the query option. This way, you control when the fetch is triggered.
3. Debounce updates: If appropriate, debounce the updates to the reactive properties to avoid rapid consecutive changes.
4. Avoid using a reactive object directly: Pass individual refs or computed values instead of a reactive object, or use a computed getter that depends on all relevant properties.
Reference
- Reactive Fetch Options and Watchers
- Known watcher caveat and issue
- Docs: useFetch and reactivity
Summary:The double call and use of old data are due to how Vue and Nuxt handle reactivity and watchers on objects. To avoid this, batch your updates or use a computed getter that only updates after all relevant properties have changed. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@469369769351708682> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai
I have underestand the point of call twice. but when I change the pagination value with setPage method it call twice. base on the code I've offer to you. only one reactive property is changed not multiple properties
Let me check the knowledge base for you again. One moment! :books:
----------------------
You're correct that in your
Even if you only change one property, the way Nuxt and Vue handle reactivity and watchers on objects/computed properties can still result in double fetches. This is a known caveat and is being discussed and improved in the Nuxt ecosystem, but as of now, it can still happen in certain scenarios. If this behavior is problematic, consider using a single ref for the page index in your query, or use a watcher to control when the fetch should be triggered, as a workaround until the underlying watcher behavior is improved in Nuxt. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
setPage method, only pagination.value.pageIndex is being changed. However, the double call can still occur due to how Nuxt's useFetch watches reactive dependencies, especially when using a computed object for the query option.
When you use a computed property for query, Nuxt automatically watches all its dependencies. Even if you only change one property, the watcher may trigger a fetch twice: once for the old value and once for the new value. This is a known issue, especially after changes in Nuxt 3.17.2 and 4.x, where watcher flush timing and deduplication logic can cause a fetch to be triggered with stale data before the new value is fully applied. This behavior is discussed in detail in this GitHub issue.
Additionally, if you use a reactive object (like your pagination state) in a computed, Vue's reactivity system may trigger the watcher on any property change, and Nuxt's internal watcher may not always batch these changes as expected, leading to multiple fetches.
Key points from the knowledge sources:
- "The watcher executes straight away on the first change before the rest of the object has been modified (which is indeed exactly what is happening)" [Github Issue].
- "When you use a computed ref or a plain ref as the URL, allowing for dynamic data fetching that automatically updates when the URL changes" [Nuxt Docs].
- "When reactive fetch options are provided, they'll be automatically watched and trigger refetches" [Nuxt Docs].
In summary:Even if you only change one property, the way Nuxt and Vue handle reactivity and watchers on objects/computed properties can still result in double fetches. This is a known caveat and is being discussed and improved in the Nuxt ecosystem, but as of now, it can still happen in certain scenarios. If this behavior is problematic, consider using a single ref for the page index in your query, or use a watcher to control when the fetch should be triggered, as a workaround until the underlying watcher behavior is improved in Nuxt. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@469369769351708682> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai
can you offer me a new code for useFetch base on my compoable?
only the useFetch that work with other exist codes
Let me check the knowledge base for you again. One moment! :books:
----------------------
Certainly! Based on your composable and the knowledge sources, the recommended approach is to avoid passing a computed object directly as the
query option to useFetch, as this can cause multiple fetches due to how Vue's reactivity system works. Instead, you can use individual refs for each query parameter, which are watched more predictably by Nuxt.
Here’s how you can rewrite the useFetch part of your composable:
Key points:
- Each query parameter is a ref or computed, not a computed object containing all parameters.
- This approach is supported and recommended in the Nuxt documentation for reactive fetch options [Nuxt Docs: Reactive Fetch Options].
- This should help avoid the double-fetch issue when only one property changes.
Reference:Fetch options can be provided as reactive, supportingIf you still experience double calls, you may consider using thecomputed,refand computed getters. When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value.
— Nuxt Docs: useFetch - Reactive Fetch Options
watch option to have more explicit control over when the fetch is triggered [Nuxt Docs: Watch].
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@469369769351708682> Kapa.ai is still learning and improving, please let me know how I did by reacting below.