Martin at Mennt
Martin at Mennt

Reputation: 5737

Nested useFetch in Nuxt 3

How do you accomplish nested fetching in Nuxt 3? I have two API's. The second API has to be triggered based on a value returned in the first API.

I tried the code snippet below, but it does not work, since page.Id is null at the time it is called. And I know that the first API return valid data. So I guess the second API is triggered before the result is back from the first API.

<script setup>
  const route = useRoute()
  const { data: page } = await useFetch(`/api/page/${route.params.slug}`)
  const { data: paragraphs } = await useFetch(`/api/page/${page.Id}/paragraphs`)
</script>

Obviously this is a simple attempt, since there is no check if the first API actually return any data. And it is not even waiting for a response.

In Nuxt2 I would have placed the second API call inside .then() but with this new Composition API setup i'm a bit clueless.

Upvotes: 8

Views: 13708

Answers (3)

wobsoriano
wobsoriano

Reputation: 13462

You can set your 2nd useFetch to not immediately execute until the first one has value:

<script setup>
  const route = useRoute()
  const { data: page } = await useFetch(`/api/page/${route.params.slug}`)
  const { data: paragraphs } = await useFetch(`/api/page/${page.value?.Id}/paragraphs`, {
    // prevent the request from firing immediately
    immediate: false,
    // watch reactive sources to auto-refresh
    watch: [page]
  })
</script>

You can also omit the watch option there and manually execute the 2nd useFetch. But for it to be reactive, pass a function that returns a URL instead:

const { data: page } = await useFetch(`/api/page/${route.params.slug}`)
const { data: paragraphs, execute } = await useFetch(() => `/api/page/${page.value?.Id}/paragraphs`, {
  immediate: false,
})

watch(page, (val) => {
  if (val.Id === 69) {
    execute()
  }
})

You should never invoke composables inside lifecycle hooks.

More useFetch options can be found here.

Upvotes: 8

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You could watch the page then run the API call when the page is available, you should paragraphs as a ref then assign the destructed data to it :

<script setup>
const paragraphs = ref()

const route = useRoute()

const { data: page } = await useFetch(`/api/page/${route.params.slug}`)


watch(page, (newPage)=>{
    if (newPage.Id) {

      useFetch(`/api/page/${newPage.Id}/paragraphs`).then((response)=>{
         paragraphs.value  = response.data

     })
        
    }
}, {
    deep: true,
    immediate:true
})
</script>

Upvotes: 6

Steven Spungin
Steven Spungin

Reputation: 29159

One solution is to avoid using await. Also, use references to hold the values. This will allow your UI and other logic to be reactive.

<script setup>
  const route = useRoute()
  const page = ref()
  const paragraphs = ref()
  useFetch(`/api/page/${route.params.slug}`).then(it=> {
     page.value = it
     useFetch(`/api/page/${page.value.Id}/paragraphs`).then(it2=> {
        paragraphs.value = it2
     }
  }
</script>

Upvotes: 4

Related Questions