kabugh
kabugh

Reputation: 315

How to display loaded data after page refresh in vue?

I have a component with some items and those items are loaded from api using get request method. When I click on an item I get redirected to its own page using dynamic routing: { path: '/:id', component: Item }. Clicked item is recognised using currentItem() method: currentItem() { this.items.find(item => item.code === this.$route.params.id) } where item.code is a property I get from api. My problem is that when I refresh the page with current item, it is not loaded anymore. I tried using beforeCreate() to load items one more time in their own component. Maybe I could use a watch to change the state depending on the item?

beforeCreate() {
    this.$http.get(url).then(response => {
          this.items = response.body;
    }
},
watch: {
    '$route' (to, from) {
      this.currentItem()
    }
  }

Here's a demo.

Upvotes: 2

Views: 7534

Answers (1)

Max Sinev
Max Sinev

Reputation: 6034

You should add watch for $route to react to id changes when you navigate between pages. But in this case there is a chance that currentItem return null because your request will have ended after watch handler already invoked.

First solution is to watch items collection in Item component and invoke this.currentItem() in this watch handler. And yes, you will have to load items in your Item component like in your example.

Second one is use computed property currentItem instead method if it's possible:

computed: {
   currentItem() {
       return this.items.find(item => item.code === this.$route.params.id)
   }
}

This will be reactive and you don't need watch anymore. But don't forget to make this.items empty array by default to avoid null errors.

The third solution is combination second one with using Vuex store to share items collection between all components and do something like this:

beforeCreate() {
    // you should check in this action that items already loaded earlier as well
    this.$store.dispatch('loadItems');
},
computed: {
   currentItem() {
       return this.items.find(item => item.code === this.$route.params.id)
   },
   items() {
       return this.$store.state.items
   }
}

Store:

state: {
   items: [],
   itemsLoaded: false,
}
actions: {
   loadItems({state, commit}) {
      // avoid unnecessary loading between navigations
      if (itemsLoaded) return
      Vue.http.get('some url').then(response => {
          commit('setItems', response.body);
          commit('itemsLoaded');
      }
   }
},
mutations: {
   setItems: (state, items) => state.items = items 
   itemsLoaded: (state) => state.itemsLoaded = true
}

So you dont need to store items in both Item and Items components for example.

Sorry for long post.

Upvotes: 1

Related Questions