Skip to content

[useFetch/useAsyncData] Watched params breaks watcher/js expected synchronicity #33189

@Tofandel

Description

@Tofandel

Environment

  • Operating System: Linux
  • Node Version: v24.1.0
  • Nuxt Version: 3.19.1
  • CLI Version: 3.28.0
  • Nitro Version: 2.12.5
  • Package Manager: [email protected]
  • Builder: -
  • User Config: -
  • Runtime Modules: -
  • Build Modules: -

Reproduction

Screen.Recording.2025-09-09.202618.mp4
  const category = ref('foo');
  const locale = ref('en');
  const params = reactive({});

  watch(
    category,
    () => {
      params.category = category.value || null; // 1
      params.locale = locale.value; // 3
    },
    { immediate: true },
  );

  const fetchCategories = async () => {
    const { data } = await useFetch('/api/categories', {
      params,
      dedupe: 'defer',
      onRequest: () => (console.log(params.locale, params.category)) // 2
    });
    return data;
 }
 
 await fetchCategories();
 locale.value = 'hu';
 category.value = 'bar';

Given the following code, any developer would expect 2 requests to be made

  1. /api/categories?category=foo&locale=en
  2. /api/categories?category=bar&locale=hu

But this is not what happens, the request is started right after params.category is updated and before params.locale is fully updated resulting in

  1. /api/categories?category=foo&locale=en
  2. /api/categories?category=bar&locale=en

And because of the debounce, the watcher is then not even called again a 3rd time with the correct parameters (kind of a separate bug, it seems debounce should be a throttle instead)

Describe the bug

Basically the request fires too early while the callback of another watcher is still running.
The bug seems to stem from the flush: sync parameter in the watcher of useAsyncData


(This one may also cause issues)
watch([...watchSources, _fetchOptions], setImmediate, { flush: 'sync', once: true })

https://vuejs.org/guide/essentials/watchers#sync-watchers

The warning is pretty clear in the doc that this should not be used for objects or arrays as there is no batching meaning 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)

Additional context

This issue has caused me many headaches because the requests parameters are not aligned with what I expected after upgrading causing 400 and 404 requests and the workarounds are very verbose (needing an intermediate object updated at once in another watcher)

It has been introduced by 888383e (3.17.2 and 4.0.0+)

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions