Search code examples
javascriptvue.jsvuejs3nuxt.jsnuxt3.js

Same useAsyncData vs useFetch but useAsyncData doesn't fetch on the first load or hard refresh. Why?


I have these two functions and I think they are identical. However, it seems that the useLazyAsyncData function does not trigger the API call upon the first load; it only does so if I navigate away and then back again.

Please note that I used lazy on both and removing the lazy didn't seem to change the outcome.

Do you have any ideas on what mistakes I might be making?

const {
  status,
  data: airlines,
  error,
  refresh
} = useFetch('/api/airlines/list', {
  params: queryItems,
  transform: (airlines: ListResult<Airline>) => transformer(airlines)
})

const {
  status,
  data: airlines,
  error,
  refresh
} = await useAsyncData(
  'airlines',
  () =>
    $fetch('/api/airlines/list', {
      params: queryItems
    }),
  {
    transform: (airlines: ListResult<Airline>) => transformer(airlines)
  }
)

My understanding is that useAsyncData gives you more options for more control and as per Daniel Roe who leads the Nuxt team: https://github.com/nuxt/nuxt/discussions/16063#discussioncomment-2481828 "useFetch(url) is exactly equivalent to useAsyncData(url, () => $fetch(url)) - it's DX for the most common use case."

One of the SO questions linked above notes that useAsyncData automatically caches the data - and I'm wondering if there is a subtle difference I'm missing.

I've even tried to simplify my useAsyncData request to its simplest form to see if it fetches:

const { status, data: airlines, error, refresh } = await useAsyncData('airlines', () => $fetch('/api/airlines/list'))

But no dice, even if I refresh the page, but if I navigate to the page it will execute. While useFetch continues to work flawlessly both in its simplest form and the more complex options indicated above.


Solution

  • I’ve been running into an issue where useAsyncData doesn't seem to trigger the API call on the first load. It only fires when I navigate away from the page and then come back. I’ve been comparing it to useFetch, which works as expected, but for some reason, useAsyncData seems to act differently.

    Here’s what I’ve learned. The main difference between these two functions is how they handle caching.

    With useFetch, it’s designed more for client-side fetching, so it doesn’t cache the data automatically. Every time the page loads, it fetches new data unless you explicitly cache it. This makes it pretty straightforward and predictable, especially if you always need fresh data.

    On the other hand, useAsyncData is optimized for server-side rendering (SSR) and automatically caches data. When the page first loads, it runs on the server, fetches the data, and caches it. If you visit the page again or refresh it, Nuxt uses the cached data instead of making a new API call. That’s why it might seem like the data isn’t being fetched when the page first loads—it’s probably being pulled from the cache.

    If you want useAsyncData to work more like useFetch and fetch new data on every load, you need to disable that caching behavior. Here’s how you can do that:

    const { status, data: airlines, error, refresh } = await useAsyncData('airlines', () => 
      $fetch('/api/airlines/list'), {
        key: 'airlines',
        lazy: false, 
        immediate: true, 
        watch: false, 
        default: () => []
      }
    )

    By setting immediate: true and disabling caching (watch: false), you should be able to force it to fetch data on every load. You can also use the refresh function if you need to manually re-fetch the data.

    If you’re just looking for client-side fetching, though, useFetch is probably the better option. It works more predictably in that scenario, always triggering the API call when you need it.

    So, the issue boils down to caching behavior in useAsyncData, and if you’re not careful, it can make it seem like the API isn’t being called when it actually is, but from a cache. Just tweak the config, and you should be good to go.