UseAsyncData - undefined Ref

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 }
}
// 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 }
}
No description
2 Replies
kapa.ai
kapa.ai5w ago
Hi @AxelSorensen. 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
}
})
}
// 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:
const { data: episodes } = await useEpisodesFromSeason(seasonId, ep_limit, order, key)
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: ----------------------
kapa.ai
kapa.ai5w ago
<@558317900943982593> 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