Help issuing consecutive api requests, where the second is dependent on the first
Hi y'all. I'm having a heck of a time figuring out the best way to issue 2 consecutive API calls on a nuxt3 page where the second call is dependent on data from the first. It's important to me that all of the data be rendered via SSR, and also fetched lazily when browsing on the client.
I've got 2 custom composables that wrap
useLazyFetch()
. The first fetches an album
by slug
, and the second fetches photos
using the album.id
.
For example:
I thought that await
would allow them to operate consecutively, and they often do... but I'm running into rare instances where the value of the album_id
is not being passed into the useGetPhotos
call... as if the first query has not completed before the second is kicked off.
I've also tried fetching this data in various other ways that i can explain further, but am very curious about the recommended approach for issuing subsequent queries like this.3 Replies
Hi @broox. 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 knowledge sources provided, I can offer some insights and recommendations for your issue with consecutive API calls in Nuxt 3.
The problem you're experiencing is likely related to the way
useFetch
and useAsyncData
work in Nuxt 3. These composables are designed to be called directly in the setup function, and they handle adding responses to the Nuxt payload for server-side rendering. However, when using multiple calls that depend on each other, you might encounter issues like the one you described.
Here are a few approaches you can consider:
1. Use a single useAsyncData
call:
Instead of making two separate calls, you can combine them into a single useAsyncData
call. This ensures that all data is fetched before rendering. Here's an example based on the Docs > Api > Composables > useAsyncData (https://nuxt.com/docs/api/composables/use-async-data) source:
This approach ensures that the second API call is only made after the first one completes.
2. Use Promise.all
with useLazyAsyncData
:
If you prefer to keep your custom composables, you can use Promise.all
to ensure both calls are completed before proceeding. This approach is mentioned in a comment from the Github Issue: useAsyncData and useFetch run twice if page uses layout (https://github.com/nuxt/nuxt/issues/13369) source:
3. Use a computed URL:
If the second API call's URL depends on the result of the first call, you can use a computed URL as described in the Docs > Getting-started > Data Fetching > Computed URL (https://nuxt.com/docs/getting-started/data-fetching#computed-url) source:
This approach ensures that the second fetch is only called when the album data is available.
Remember that when using these approaches, you should avoid awaiting custom composables that wrap useFetch
or useAsyncData
, as mentioned in the Docs > Api > Composables > useFetch (https://nuxt.com/docs/api/composables/use-fetch) source.
Lastly, be cautious about using watch
with useFetch
, as it can lead to unexpected behavior, as noted in the Github Issue: useFetch automatic request after first request (https://github.com/nuxt/nuxt/issues/15741) source.
By implementing one of these approaches, you should be able to ensure that your consecutive API calls work correctly, with the second call always depending on the result of the first, while maintaining SSR compatibility and lazy loading on the client side.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@357175353749274635> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
nice portishead shirt 🙂
and if i understand correctly, i cannot conditionally call my
useGetPhotos
composable in a watch statement. is there a way to do this while using my composables?
i tried moving the useGetPhotos
call into a child component that is rendered on the page to isolate it. this seemed to work, however i want some data from the useGetPhotos
call to be available on the parent page via SSR (e.g. the composable status
and a photoCount
that is returned by the API call).
i tried various approaches to acheiving this, using provide/inject
, defineExpose
, etc. but was running into weirdness where these values were not rendered on the server. they were available on the client though.
why is that? doesn't useLazyFetch
use useFetch
on the server side, but allows navigation to feel snappier on the client side while data is loading?
word, i understood that it used useFetch
and $fetch
(ofetch
) under the hood, but it has worked reliably for me with SSR thus far.
the only place i'm having trouble is where i have dependent requests, and the main reason that i would like to use my composables is that they handle pagination, caching, etc, and i call them from many different places.
moving the second composable into a child component has seemingly been the most reliable way for me issue the 2 requests, however sharing the state from the child component to the parent has been unreliable on the server side.
i can play with immediate
and watch
to execute the second query once i am sure album_id
is set
this works, but not on SSR. as expected, i suppose.
it does feel weird that await
does not truly await the first query to complete when immediate
is true. but i guess it makes sense
right now, the best way for this to work, in my mind is to move the second composable to a child component and attempt to send relevant metadata up to the parent... but i am also having issues with the parent rendering that data on the server side.
for now, i solved this by splitting the queries into a parent page that almost exclusively just fetches the album
via one composable... and then pushing all the other logic, including the composable that loads the photos
into child component.
yea, i read that earlier. thanks for the tips.