Loading data from axios call using <script setup> syntax

Hi everyone!

I’m having trouble using the <script setup> syntax when it comes to loading data from an async API call. I think I’m missing some fundamental understanding. I know that, despite reading the docs, and using other resources, I don’t quite understand the reactivity system.

Here is my component:

<template>
    <h1>{{eventdetails.title}}</h1> <!-- eventdetails.title never gets updated here. This is the problem. -->
</template>

<script setup lang="ts">
import {getEvent} from "../services/EventService";
import {reactive} from 'vue'
import {HEvent} from "../types";

let eventdetails = reactive({} as HEvent)

getEvent(1) // A helper function that uses axios to make an API call, returns a Promise. Here I'm passing a hardcoded '1' to get the event with id 1
    .then(response => {
      eventdetails = response.data
      console.log(eventdetails) //shows that eventdetails has been correctly updated
    })
    .catch(error => {
      console.log(error)
    })

</script>

The problem is that in the template {{eventdetails.title}} never gets updated with the data from the call.

I’ve tried initializing the eventdetails variable in other ways:
let eventdetails = reactive({})
let eventdetails = ref({})
let eventdetails = {}

I have also tried placing the getEvent() call within an onMounted hook (although I don’t think that should be necessary), but it didn’t work.

What am I doing wrong?

Try using Object.assign(eventdetails, response.data)

Thanks, that works.

But why that works, but not plain assignment is still a mystery to me. In another instance I wanted to assign the value to an array (which should be reactive) and I had to use Array.push in combination with the spread operator to make it work. So I’m definitely gonna have to do some more reading on the reactivity system.

All that being said, I did find the more “official” way to get this done, which I will post below.

Here is the solution to my issue:

<template>
    <h1>{{eventdetails.title}}</h1>
</template>

<script setup lang="ts">
import {getEvent} from "../services/EventService";
import {ref} from 'vue'
import {HEvent} from "../types";

let eventdetails = ref({} as HEvent)

getEvent(1)
    .then(response => {
      eventdetails.value = response.data
      console.log(eventdetails)
    })
    .catch(error => {
      console.log(error)
    })

</script>

Note the use of ref() instead of reactive(), and also note that in assigning the API response to the eventdetails variable I use eventdetails.value = response.data instead of eventdetails = response.data .

In your original component example, you overwrote your reactive object. The assign method preserves the original object and updates the properties. The ref uses the value accessor to achieve a similar result but wipes out all old properties.

1 Like

Ah, makes sense!

I’m unaware of this assign method, and I haven’t been able to find it in the docs. How is it used?

1 Like