N
Nuxt4d ago
kozy

useAsyncData with pinia

I was reading through the documentation on useAsyncData and I noticed that it mentioned:
useAsyncData is for fetching and caching data, not triggering side effects like calling Pinia actions, as this can cause unintended behavior such as repeated executions with nullish values. If you need to trigger side effects, use the callOnce utility to do so.
with the following example:
const offersStore = useOffersStore()

// you can't do this
await useAsyncData(() => offersStore.getOffer(route.params.slug))
const offersStore = useOffersStore()

// you can't do this
await useAsyncData(() => offersStore.getOffer(route.params.slug))
I'm curious if you could provide more explanation on this... Specifically, if the presence of a key/or a single fetch without any computed url changes things. In my case, I don't want to the call to block the route e.g.,
const userStore = useUserStore()

await useAsyncData('offers', store.getUser, {
lazy: true
})
const userStore = useUserStore()

await useAsyncData('offers', store.getUser, {
lazy: true
})
I'm aware I could move the logic out of the store and leverage the built-in cache from useFetch / useAsyncData. Would something like this work as well?
const useUserStore = defineStore('use', () => {
const user = ref<User>()

function fetchUser() {
// useFetch instead of $fetch
const { data } = useFetch('', { lazy: true })
user.value = data.value
}
})

// script setup
await callOnce(async () => {
await store.fetchUser()
})
const useUserStore = defineStore('use', () => {
const user = ref<User>()

function fetchUser() {
// useFetch instead of $fetch
const { data } = useFetch('', { lazy: true })
user.value = data.value
}
})

// script setup
await callOnce(async () => {
await store.fetchUser()
})
Nuxt
Data Fetching · Get Started with Nuxt
Nuxt provides composables to handle data fetching within your application.
2 Replies
kapa.ai
kapa.ai4d ago
Hi @kozy. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- You're asking about the proper way to use useAsyncData with Pinia stores in Nuxt, which is a great question since this can be a source of confusion. Why not to use useAsyncData with Pinia actions The documentation warns against using useAsyncData with Pinia actions because: 1. useAsyncData is designed specifically for data fetching and caching, not for triggering side effects 2. If a Pinia action returns undefined or a nullish value, useAsyncData may re-execute, causing repeated calls to the same action 3. This can lead to unintended behavior in your application Using callOnce instead Your second approach using callOnce is the recommended way to handle this scenario. The callOnce utility was specifically designed to execute code only once during: - Server-side rendering (but not hydration) - Client-side navigation
const useUserStore = defineStore('use', () => {
const user = ref<User>()

function fetchUser() {
// useFetch instead of $fetch
const { data } = useFetch('', { lazy: true })
user.value = data.value
}
})

// script setup
await callOnce(async () => {
await store.fetchUser()
})
const useUserStore = defineStore('use', () => {
const user = ref<User>()

function fetchUser() {
// useFetch instead of $fetch
const { data } = useFetch('', { lazy: true })
user.value = data.value
}
})

// script setup
await callOnce(async () => {
await store.fetchUser()
})
This approach is correct because: 1. callOnce ensures your store action is only called once during rendering 2. Inside your store, using useFetch properly handles the data fetching with Nuxt's caching mechanism 3. The lazy: true option prevents blocking navigation As mentioned in the documentation, callOnce is specifically useful in combination with Pinia to call store actions Docs > Api > Utils > callOnce. Alternative approach If you want to keep your data fetching logic in your component rather than the store, you could also do:
// In your component
const userStore = useUserStore()
const { data } = await useFetch('/api/user', {
lazy: true,
transform: (data) => {
// Update store after fetching
userStore.setUser(data)
return data
}
})
// In your component
const userStore = useUserStore()
const { data } = await useFetch('/api/user', {
lazy: true,
transform: (data) => {
// Update store after fetching
userStore.setUser(data)
return data
}
})
This way, you're using useFetch for what it's designed for (data fetching) and then updating your store as a side effect through the transform function. Remember that useFetch is essentially a wrapper around useAsyncData and $fetch, providing a cleaner API for the most common use case Docs > Getting-started > Data Fetching. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@357629012987740161> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?