N
Nuxtβ€’4w ago
DesiredName

useAsyncData in composables that uses each other

Hi, everyone! πŸ™‚ I have a repo here: https://gitlab.com/HIV/budgettracker The description: I have a composable useTransactionGroups (B) and useTransactions (A) Both of them are supposed to run server-side on initial load. (B) uses (A) to compute groups property. (B) is used on transactions page and the (A) is used in the TFilter component. the transactions data is requested with useAsyncData that (as per docs) is supposed to use useState for the data it fetches to cache it. The problem: Whenever the app starts, it issues 2 requests to transactions API endpoint from (A), because: TFilter -> (A): filters Transactions (page) -> (B): groups -> (A): transactions What did I try: 1. use pinia store to join (A) + (B) data inside in one shot; 2. use closures in (A) and (B) to not to create two separate instances of (A); 3. use useSatate to manage data inside (A) and (B) If I use only (B) inside transactions page and pass filter and groups as props to the corresponding components, everything works great. The question: What are the options to 'tear apart' single composable with useAsyncData inside. I think I don't understand something and maybe composables are not even designed to work that way. Thank you!
2 Replies
kapa.ai
kapa.aiβ€’4w ago
Hi @DesiredName. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the information provided in the knowledge sources, I can offer some insights and suggestions regarding your question about using useAsyncData in composables that depend on each other. The main issue you're facing is that multiple requests are being made to the same API endpoint, which is not the desired behavior when using useAsyncData. This composable is designed to cache data and avoid duplicate requests. Let's explore some potential solutions: 1. Use a unique key for useAsyncData: One of the most important aspects of using useAsyncData effectively is to provide a unique key. As mentioned in the Nuxt documentation (https://nuxt.com/docs/getting-started/data-fetching#suspense), it's recommended to always create your own key to avoid unwanted behavior, especially when creating custom composables that wrap useAsyncData. Try modifying your composables to use a consistent, unique key for the transactions data:
const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
})

const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
})

Ensure that this key is used consistently across both composables. 2. Use useNuxtData to access cached data: Instead of making separate calls in each composable, you can use useNuxtData to access the cached value of a previous useAsyncData call. This is explained in the useNuxtData documentation (https://nuxt.com/docs/api/composables/use-nuxt-data). In your case, you could fetch the transactions data in composable A, and then access it in composable B using useNuxtData:
// Composable A
const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
})
// Composable B
const { data: cachedTransactions } = useNuxtData('transactions')
// Use cachedTransactions.value to compute groups

// Composable A
const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
})
// Composable B
const { data: cachedTransactions } = useNuxtData('transactions')
// Use cachedTransactions.value to compute groups

3. Use the dedupe option: The useAsyncData composable has a dedupe option that can help prevent multiple simultaneous requests. As mentioned in the useAsyncData documentation (https://nuxt.com/docs/api/composables/use-async-data), you can set dedupe: 'defer' to avoid making new requests if there's already a pending request:
const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
}, { dedupe: 'defer' })

const { data: transactions } = await useAsyncData('transactions', () => {
return myGetFunction('transactions')
}, { dedupe: 'defer' })

4. Consider using sharedPrerenderData: If you're prerendering your site, you might benefit from enabling the sharedPrerenderData experimental feature. As described in the Nuxt configuration documentation (https://nuxt.com/docs/api/nuxt-config#sharedprerenderdata), this can help share payload data between pages that are prerendered, potentially reducing duplicate requests. 5. Refactor your composables: Consider restructuring your composables to have a single source of truth for the transactions data. You could create a base composable that fetches the transactions, and then have composables A and B extend or use this base composable. Remember, when using useAsyncData in composables, it's crucial to follow the guideline mentioned in the Stack Overflow post (https://stackoverflow.com/questions/77949232): avoid using await before calling a composable. This can lead to errors when multiple useAsyncData calls are made. If these suggestions don't fully resolve your issue, you might need to take a closer look at how your composables are structured and how they're being used in your components. The ideal solution would be to have a single source of truth for your transactions data that both composables can reliably access without triggering duplicate requests. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’4w ago
<@457147380479950848> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server