Home > front end >  Using Vue Transition Group on Data Returned from Api Endpoint
Using Vue Transition Group on Data Returned from Api Endpoint

Time:07-31

I have an api endpoint that I built that returns a list of products and everything there is working just fine. I tried to use this github link to get a working example because the endpoint I am using is not publicly available.

In my case, lets say we could hit this fictional endpoint: https://api.github.com/orgs/vuejs/repos?id=123456, one repo would be returned and what happens is it would appear immediately. How could we get the new items to fade in rather than immediately appearing on subsequent requests?

For the sake of this example, how could we make the repos fade in without actually wrapping the v-if element and the v-else element with <transition>? There should be a transition when this.response = data happens

const { createApp } = Vue

createApp({
  data() {
    return {
      response: null,
      loaded: false
    }
  },
  methods: {
    fetchData() {
      fetch('https://api.github.com/orgs/vuejs/repos')
        .then(response => response.json())
        .then(data => {
          this.response = data;
          this.loaded = true;
       })
    }
  },
  mounted() {
    this.fetchData();
  },
}).mount('.repo-wrapper')
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
 }

.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}
<script src="https://unpkg.com/vue@3"></script>

<div >
  <div v-if="!loaded" >LOADING...</div>

  <div v-else>
    <transition-group name="fade">
      <div v-for="(repo, index) in response" :key="repo.id">
          <a :href="repo.html_url" :title="repo.description" target="_blank">
    {{ repo.name }}
          </a>
        </div>
       </transition-group>
      </div>
</div>

CodePudding user response:

Problem is transition-group is applying transitions to individual items of already rendered list. When you fetch your data, the list is not rendered at all as it is hidden after v-else and when it shows for the first time, that does not count as list change

See example below with changes:

  1. response initial value is [] instead of null
  2. v-for is rendered no matter if data is loaded or not

It works!

const { createApp } = Vue

createApp({
  data() {
    return {
      response: [],
    }
  },
  methods: {
    fetchRandom() {
      this.fetchData(Math.floor(Math.random() * 20))
    },    
    fetchData(pageSize = 10) {
      fetch(`https://api.github.com/orgs/vuejs/repos?per_page=${pageSize}`)
        .then(response => response.json())
        .then(data => {
          this.response = data;
       })
    }
  },
  mounted() {
    this.fetchData();
  },
}).mount('.repo-wrapper')
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
 }

.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 1s ease;
}
<script src="https://unpkg.com/vue@3"></script>

<div >
  <button @click="fetchRandom">Reload</button>  
  <ul>
    <transition-group name="fade">
      <li v-for="(repo, index) in response" :key="repo.id">
          <a :href="repo.html_url" :title="repo.description" target="_blank">
    {{ repo.name }}
          </a>
        </li>
       </transition-group>
      </ul>
</div>

  • Related