Here is a brief summary:
You cannot reassign a reactive object because it will break the reactivity and cause the old references to lose their connection to the object's value. Therefore, it is recommended to declare all reactive variables using const
.
It appears that the logic you have provided is overly complex. In my understanding, the loading
variable should be set to true when axios
is in the process of loading data. Make sure that your imports are correct:
<template>
<div @click="loadEvents">{{ loading }}</div>
</template>
<script setup>
const loading = ref(false);
loadEvents()
async function loadEvents() {
loading.value = true;
const results = await backendApi.getEvents(selectedDate.value);
// perform actions with results here
loading.value = false;
}
function getEvents() {
return axios.get(...);
}
</script>
However, there is room for improvement by refactoring the code and reusing the loading
variable within the backend api:
// backend-api.js file:
export const loading = ref(false);
export const backendApi = {
getEvents(){
return this.callApi(...);
},
async callApi(...args){
loading.value = true;
const result = await axios.get(...args);
loading.value = false;
return result;
}
};
// component file
<template>
<div @click="loadEvents">{{ loading }}</div>
</template>
<script setup>
import {loading, backendApi} from './backend-api.js';
loadEvents()
async function loadEvents() {
const results = await backendApi.getEvents(selectedDate.value);
// perform actions with results here
}
</script>
UPDATE
After some discussion with the original author, a new solution has emerged.
It was highlighted that each backend call requires its own loading reference. Moving the loading variable into the backend api might not be ideal as it can introduce dependency coupling. One recommended approach is to use setters with promise-based actions. For instance, creating a utility function like promiseRef()
can help manage loading states independently. Here is how the modified setup looks:
<script setup>
import { backendApi } from './backend-api.js';
import { promiseRef } from './utils.js'
const loading = promiseRef();
async function loadEvents(){
const result = await (loading.promise = backendApi.getEvents());
// utilize the fetched results
}
</script>
<template>
<button @click="loadEvents">{{ loading }}</button>
</template>
backend-api.js:
// This is a simulated API call
export const backendApi = {
getEvents(){
return new Promise(resolve => setTimeout(resolve, 2000));
}
}
utils.js:
import { ref } from 'vue';
export const promiseRef = value => {
const loading = ref(value || false);
let promise;
Object.defineProperty(loading, 'promise', {
get(){
return promise;
},
set(val){
loading.value = true;
(promise = val).then(() => loading.value = false);
}
});
return loading;
};
View a working example on Vue3 gist!