Samuele B.
Samuele B.

Reputation: 658

Vue - displaying old data while loading new one

Let's say in my Vue3 app I have a store whose state looks like this:

const store = {
    state () => ({
        items: []
    }),
    // ...
}

My App.vue has a single <router-view /> as its only template content.

Then I have an ItemList.vue view which looks like this:

<template>
    <div v-if="!loading">
    <Item
        v-for="item in items"
        :key="item.id"
        :item="item"
        ></Item>
    </div>
    <Skeleton v-else />
</template>

<script>
import Item from "...";
import Skeleton from "..."

import { mapState } from "vuex";

export default defineComponent({
  name: "CourseList",
  mixins: [loadingMixin],
  components: {
    Item, Skeleton
  },
  async created() {
   this.loading = true
   this.$store.dispatch("getItems", {
       categoryId: this.$route.params.categoryId
   })
   this.loading = false
  },
  data() {
    return {
      loading: false,
    };
  },
  computed: {
    ...mapState(["items"])
  },
});
</script>

Essentially, the app allows you to navigate to URLs of the form categories/<id>/items and retrieve items for that category. The items currently being viewed are stored in a flat array in the store. Every time the ItemList component is created, an action is dispatched which simply makes an API call to the items endpoint for that category and saves the result in the store's state items attribute. While this is happening, a skeleton is shown to the user.

The issue with this approach is that, while the user always gets fresh data because they are fetching the items every time they naviage to the view, there is also the inconvenience that if the data for the category hasn't changed, they are still going to be looking at the skeleton until the items are re-fetched.

If the user clicks a router-link and goes to another view that doesn't involve fetching items then comes back to the item list view for the same category as the last one they visited, I'd like them to not have to wait to see the data. I would still like the app to do the fetching, but display the existing data meanwhile. Of course, since I'm saving a single array of items, if the user goes to the list for another category, that data must not be displayed and the user must see the skeleton from the get go.

Can this be done in Vue? I tried using the <keep-alive> component and giving it a :key corresponding to the route's category id param but it didn't work.

Upvotes: 0

Views: 1083

Answers (1)

Pouya M
Pouya M

Reputation: 385

If you know which categories user have visited, you can conditionally change loading state, if not, create a set in vuex and keep previous categoryId to it.

async created() {
   if( the category has changed){ 
      this.loading = true
   }

   this.$store.dispatch("getItems", {
      categoryId: this.$route.params.categoryId
   })
   
   this.loading = false
}

Upvotes: 1

Related Questions