#UseAsyncData - undefined Ref

5 messages · Page 1 of 1 (latest)

regal bison
#

I am using vuefire to fetch data from firebase. I have been using useAsyncData inside of a custom composable to hide away my caching logic etc. This works fine for usecases where I only need to do one "useCollection" or "useDocument" call but now I need to fetch a document of episode Id's from by database and then immediatly fetch the actual episodes based on these:

I have tracked down the problem to the season_episodes being undefined when I first open the page where I call this composable (see code below) 🤔

Is there any way to make useAsyncData wait for this variable?🙏

// composables/useEpisodes.js
import { query, doc, collection, limit, orderBy, where, documentId } from 'firebase/firestore' // adjust the imports based on your setup

export async function useEpisodesFromSeason(seasonId: string, ep_limit: number, order: 'asc' | 'desc', key: string) {
    const db = useFirestore()
    const nuxt = useNuxtApp()
    const { data: episodes } = await useAsyncData(key, async () => {
        const seasonDocRef = doc(db, 'seasons', seasonId)
        const season_episodes = useDocument(seasonDocRef, { once: true })
        // season_episodes is undefined on the first page load and therefore the query below doesn't work

        const q = query(collection(db, 'episodes'), where(documentId(), 'in', season_episodes.value.data.episodes), limit(ep_limit), orderBy('date', order))
        return useCollection(q, { once: true, ssrKey: key })

    }, {

        transform: (data) => {
            return {
                data,
                fetchedAt: Date.now(),
            }
        },
        getCachedData: (key) => {
            const cachedData = nuxt.payload.data[key] || nuxt.static.data[key]
            if (!cachedData) {
                return
            }
            // if (Date.now() - cachedData.fetchedAt > 1000 * ) { // 1 minute cache
            //     return
            // }
            return cachedData
        }

    })

    return { episodes }
}
regal grottoBOT
#

Hi @regal bison. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To address your issue with useAsyncData and the undefined season_episodes, we need to make some adjustments to your code. The problem occurs because useDocument is asynchronous, and its value is not immediately available when useAsyncData runs. Here's how we can modify your code to make it work:

  1. First, we need to await the result of useDocument before using it in the query.
  2. We'll use runWithContext to ensure the Nuxt context is available when calling Firebase-related functions.

Here's the modified version of your code:

// composables/useEpisodes.js
import { query, doc, collection, limit, orderBy, where, documentId } from 'firebase/firestore'

export function useEpisodesFromSeason(seasonId: string, ep_limit: number, order: 'asc' | 'desc', key: string) {
  const nuxt = useNuxtApp()

  return useAsyncData(key, async () => {
    return await runWithContext(async () => {
      const db = useFirestore()
      const seasonDocRef = doc(db, 'seasons', seasonId)
      const season_episodes = await useDocument(seasonDocRef, { once: true })

      if (!season_episodes.value || !season_episodes.value.data || !season_episodes.value.data.episodes) {
        throw new Error('Season episodes data is not available')
      }

      const q = query(
        collection(db, 'episodes'),
        where(documentId(), 'in', season_episodes.value.data.episodes),
        limit(ep_limit),
        orderBy('date', order)
      )
#

return useCollection(q, { once: true, ssrKey: key })
})
}, {
transform: (data) => {
return {
data,
fetchedAt: Date.now(),
}
},
getCachedData: (key) => {
const cachedData = nuxt.payload.data[key] || nuxt.static.data[key]
if (!cachedData) {
return
}
// if (Date.now() - cachedData.fetchedAt > 1000 * ) { // 1 minute cache
// return
// }
return cachedData
}
})
}


Key changes and explanations:

1. We've wrapped the Firebase-related operations inside `runWithContext`. This ensures that the Nuxt context is available when these operations are executed, which is necessary for Firebase functions to work correctly in the Nuxt environment **Source** (<https://www.youtube.com/watch?v=ofuKRZLtOdY>).

2. We've made the inner function of `useAsyncData` async and await the result of `useDocument`. This ensures that `season_episodes` is populated before we use it in the query.

3. We've added a check to ensure that `season_episodes` and its nested properties exist before using them. This helps prevent errors if the data is not available for some reason.

4. The function now returns the result of `useAsyncData` directly, so you can destructure it when calling the composable.

To use this composable, you would call it like this:

```typescript
const { data: episodes } = await useEpisodesFromSeason(seasonId, ep_limit, order, key)

This approach should resolve the issue of season_episodes being undefined on the first page load. The useAsyncData will now wait for the useDocument call to complete before proceeding with the query.

#

Remember that this solution assumes you're using Nuxt 3, as it uses the runWithContext function which is available in Nuxt 3 Source (https://nuxt.com/docs/api/composables/use-async-data).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: