The Vue data retrieved from an API using onMounted() is not initially showing up in the DOM. However, it magically appears after I make changes to the template

Hello and thank you to those taking the time to read this. I am new to Vue, so I may be overlooking something obvious here, but after being stuck for several days, I am reaching out for help.

In my SFC file, I have an onMounted function fetching data from an API (Spring Boot). The API call is successful as I can see it in the Network tab on Chrome, with the Response containing the necessary data.

Here is my AppLeague.vue file:

<template lang="">
    <div class="row">
        <div class="col-md-12">
            <h3>Leagues</h3>
        </div>
        <div class="col-md-12">
            <ul class="list-group">
                <li
                    v-for="(leagueItem, index) in leagues"
                    :key="index"
                    class="list-group-item"
                >
                    {{ index + 1 }}.{{ leagueItem.league_name }}
                    , Status:
                    {{ leagueItem.league_status }}, Code: {{ leagueItem.league_code }}
                </li>
            </ul>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onMounted } from "vue";
import customAxios from "@/lib/customAxios";

interface League {
    league_id: number,
    league_name: string;
    league_code: string;
    league_status: string;
}

let leagues: League[];

onMounted(async () => {
    await customAxios
        .get<League[]>(`account/leagues`, {
            withCredentials: true,
    })
    .then((response) => {
        leagues = response.data;
    });
});
</script>

My unique axios module:

import axios from "axios";

export const customAxios = axios.create({
    baseURL: "http://localhost:8080/api/",
});

customAxios.interceptors.response.use(
    (response) => response,
    (error) => {
        if (error.response.status === 401) {
            window.location.href = '/';
        }
        if (error.response) {
            alert(error.response.data.message);
        }
    }
);

export default customAxios;

In Google Chrome's Network tab, I can observe the HTTP 200 code and the Response:

[{"league_id":1,"league_status":"created","league_name":"Test League","league_code":"Test League Code"}]

However, when I view the rendered page, the values are not displayed initially. Instead, they appear only after I make a minor change within VSCode and save, triggering a refresh of the page where the values then appear correctly:

If you're curious, take a look at how the page looks after altering the DOM in VSCode here.

I'm seeking a solution to ensure the values are displayed upon page load without needing to manipulate the DOM. It seems that the initial empty values of let leagues: League[]; are causing this issue, requiring a DOM alteration to display the fetched data. Any suggestions on how to force the DOM to show the fetched values directly would be greatly appreciated.

I have scoured for examples involving Vue3 and ., but have come up short. Thank you!

Answer №1

According to @dan-obregon, the crucial aspect of Vue that you overlooked is its reactivity. Dan's response falls short as simply assigning the array to the reactive object won't work. In this scenario, it would be more appropriate to utilize ref:

<script setup lang="ts">
import { Ref, ref, onMounted } from "vue";
import customAxios from "@/lib/customAxios";

interface League {
    league_id: number,
    league_name: string;
    league_code: string;
    league_status: string;
}

const leagues: Ref<Array<League>> = ref([]);

onMounted(async () => {
    await customAxios
        .get<League[]>(`account/leagues`, {
            withCredentials: true,
    })
    .then((response) => {
        leagues.value = response.data;
    });
});
</script>

Answer №2

It might be beneficial to wait for the leagues value before proceeding. It's possible that you're encountering an error because the component is failing to load some values from your leagues property that haven't been fetched yet. When you save in VSCode, the component has already mounted and the leagues data has been retrieved, hence no error occurs.

One solution could be:

Add a conditional v-if statement within your component. If your axios response returns a non-empty list, then bind your data. For example, at line 6:

<template lang="">
    <div class="row">
        <div class="col-md-12">
            <h3>Leagues</h3>
        </div>
        <div v-if="leagues.length > 0" class="col-md-12">
            <ul class="list-group">
                <li
                    v-for="(leagueItem, index) in leagues"
                    :key="index"
                    class="list-group-item"
                >
                    {{ index + 1 }}.{{ leagueItem.league_name }}
                    , Status:
                    {{ leagueItem.league_status }}, Code: {{ leagueItem.league_code }}
                </li>
            </ul>
        </div>
    </div>
</template>

Answer №3

It appears that there may be an issue related to reactivity in this context.

If you are unfamiliar with reactivity, here are some helpful resources:

  • VueJS Reactivity (official documentation)
  • ref vs reactive (explained with examples for better understanding)
  • You can also search for 'vue ref reactive' to explore additional information on this topic

My suggestion would be to modify the way leagues are declared as follows:

import {reactive} from 'vue'
...
const league = reactive<Leagues[]>([])

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Experimenting with Nuxtjs application using AVA and TypeScript

I'm in the process of developing a Nuxt application using TypeScript and intend to conduct unit testing with AVA. Nonetheless, upon attempting to run a test, I encounter the following error message: ✖ No test files were found The @nuxt/typescrip ...

Inferring object types through direct values

This code example has a lot of detail: interface Coordinate { latitude: 40.7128; longitude: -74.0060; } const location: Coordinate = { latitude: 40.7128, longitude: -74.0060, }; // The inferred type would have been // { x: number; y: number; } I ...

Is it possible for a redis client to function without having a redis datastore installed?

Currently in my node web server, I am utilizing the npm module known as redis. Upon executing my code... const client = redis.createClient(); client.on("error", function (err) { console.log("Error " + err); }); client.hmset(["key", "test keys 1", "t ...

Substitute terms in a sentence according to the guidelines

Looking to transform strings based on specific rules? "Hello {{firstName}}, this is {{senderName}}." Consider the following rules: rules = { firstName: "Alex", senderName: "Tracy" } The expected output would be: "Hello Alex, this is Tracy." If yo ...

Setting up Webpack to compile without reliance on external modules: A step-by-step guide

I am facing an issue with a third-party library that needs to be included in my TypeScript project. The library is added to the application through a CDN path in the HTML file, and it exports a window variable that is used in the code. Unfortunately, this ...

Using ag-Grid's cellEditor with object values for selection

Looking to choose a user from a list of users: User.ts export class User { constructor (public id: number, public userName : string){} } The column definition appears as follows: this.columns = [ {headerName: "Assigned", field:"user ...

Is there a way to customize the Color Palette in Material UI using Typescript?

As a newcomer to react and typescript, I am exploring ways to expand the color palette within a global theme. Within my themeContainer.tsx file, import { ThemeOptions } from '@material-ui/core/styles/createMuiTheme'; declare module '@mate ...

encountering an error with hook calls within a functional component despite using hooks correctly

https://i.stack.imgur.com/iATJi.pngGreetings! I am currently working on a Next.js app using Axios and TanstackQuery. My goal is to redirect to the "/login" page when a 401 error is caught by the AxiosInterceptorInstance. The React version is 18, react-dom ...

Can someone guide me on configuring Material-UI DataGrid in React to have multiple headers with column span?

Is there a way to achieve multiple headers with column span in the Material-UI DataGrid component? view image example ...

Alter the attributes of an instance in a class using a function

Attempting to explain a simple method in TypeScript. This method should allow modification of data for any object type within the data attribute. In simpler terms, we can modify, add, or remove data based on the specified data type, and TypeScript facilit ...

A method for modifying the key within a nested array object and then outputting the updated array object

Suppose I have an array called arr1 and an object named arr2 containing a nested array called config. If the key in the object from arr1 matches with an id within the nested config and further within the questions array, then replace that key (in the arr1 ...

Introducing the concept of type-specific name inclusion

I am currently developing my Angular app using TypeScript with the goal of preventing redundancy through some form of generic handling. Here is where I am starting: class BaseProvider { api_url = 'http://localhost:80/api/FILL_OUT_PATH/:id&apo ...

Having trouble with the lodash find function in my Angular application

npm install lodash npm install @types/lodash ng serve import { find, upperCase } from 'lodash'; console.log(upperCase('test')); // 'TEST' console.log(find(items, ['id', id])) // TypeError: "Object(...)(...) is un ...

The process of sorting through an array of objects based on their specific types in TypeScript

I am working on a function that filters an array of objects based on their type property: export const retrieveLayoutChangeActions = (data: GetOperations['included']) => data.filter(d => d.type === 'layoutChangeAction') as Layou ...

Having trouble loading a lazy component in Vue3 with v-if condition?

The code is quite simple. However, I am facing an issue where the about component cannot be rendered. <template> <div id="nav"> <button @click="sh = !sh">{{ sh }}</button> <p v-if="sh">v ...

Loop through the array while handling a promise internally and ensure completion before proceeding

I am currently working on populating a response array with Firestore snapshots and creating download links for stored files within each snapshot. Despite trying various solutions involving Promises, the response array consistently ended up being null. do ...

Angular 2 Date Input failing to bind to date input value

Having an issue with setting up a form as the Date input in my HTML is not binding to the object's date value, even though I am using [(ngModel)] Here is the HTML code snippet: <input type='date' #myDate [(ngModel)]='demoUser.date& ...

The factory class is responsible for generating objects without specifying their type

I manage a factory that specializes in facilitating dependency injection. Here's an example of what it looks like: import SomeImportantObject from "./SomeImportantObject" import DataInterface from "./DataInterface" class NoodleFactory { this.depen ...

Disable the functionality of the device's back button to prevent it from going back to the

For my project, I utilize popups to display important information to the user. When a popup is displayed, how can I override the functionality of the device's back button so that instead of navigating to the previous route, it will close the popup? ...

What is the best way to pass dynamic values to a service constructor from a component?

After days of attempting to grasp 'the Angular paradigm', I still find myself struggling to understand something about services that are not singletons. It seems impossible for me to pass a runtime-determined value to a service constructor, as I ...