Angel
Angel

Reputation: 23

How to display loading gif in vue 3 composition api

I'm very new to vue. what I'm trying to do is have a loading gif while waiting for the endpoint to return.

I'm trying to use watchEffect, but I can't figure it out. If it's the right way how do I do it? If not what should I use instead?

Thanks

EDIT: Code

<template>
    <div class="player-list" :key="playerList.id" v-for="playerList in players.playerLists">
        <PlayerList :playerList="playerList" />
    </div>
</template>

<script>
import getPlayers from "@/composables/getPlayers";
import PlayerList from "@/components/PlayerList";
import { watchEffect } from 'vue';

export default {
    name: 'PlayerLists',
    components: {
        PlayerList
    },
    setup() {

        const { players, error, load } = getPlayers() //request endpoint
        load()

        watchEffect(() => {
            console.log('watch effect function')
        })

        return { players, error }
    }
}
</script>

Upvotes: 2

Views: 6763

Answers (2)

Gass
Gass

Reputation: 9344

This is an example using the latest syntax with <script setup> and computed()

<template>
    <img v-if="loading" :src="your/path.gif" />
</template>

<script setup>
import { computed, onMounted, ref } from 'vue';

const data = ref();
const loading = computed(() => data.value? true : false);

onMounted(() => {
  try{
    const resp = await fetch('your-api/url')
    data.value = resp;
  }
  catch (error){
    console.log(error);
  }
})
</script>

Similar to normal refs, you can access the computed result as loading.value. Computed refs are also auto-unwrapped in templates so you can reference them without .value in template expressions.

A computed property automatically tracks its reactive dependencies. Vue is aware that the computation of loading depends on data, so it will update any bindings that depend on loading when data changes.


In case you are having issues with the gif not been loaded from the start of the animation each time, check this here.

Upvotes: 0

matthew-e-brown
matthew-e-brown

Reputation: 2997

Vue apps should be data-driven. So, instead of relying on effects, change how your app looks by setting your data. If you're fetching some data from an endpoint, it's safe to assume you'll be putting it somewhere to display it in your app, like a Ref.

So, why not display your loading spinner as long as your Ref is not the data it is waiting to become? i.e., display a GIF while someRef == null?

<template>
  <img v-if="data === null" src="./img/loading.gif" alt="Loading" />
  <div v-else>
    <div>Here's the data!</div>
    <pre>{{ data.toString() }}</pre>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
  setup() {
    const data = ref(null);

    onMounted(() => {
      // Replace this `fetch` call with whatever your endpoint call may be.
      fetch('./endpoint')
        .then(resp => resp.json())
        .then(json => data.value = json);
    });

    return { data };
  }
};
</script>

Does that make sense? Your app should be modelling your data. You can take advantage of the fact that "a loading GIF should only be displayed while we do not have the data" to, well... display a GIF as long as the data is unset.

Upvotes: 8

Related Questions