One of the best ways to improve the user experience in a dynamic application is by setting up loading icons for data coming into your Vuex store. But if you’ve ever tried to set this up on a page with a lot of components that are loading different dynamic data. How do you show the user that data is being loaded when that data might be coming from different, parallel API calls?

Your first attempt might be to have a loading value in your Vuex store that you set to true when you are loading in data and false once the data is loaded. But that quickly becomes not good enough once you are loading in multiple calls.

And there are a number of other schemes that just don’t cut it either. Things like incrementing a loading count or checking to see if data is filled in or not–which I do talk about in How to show a loading icon before data is loaded in Vue and Vuex but is only reliable in simple data loads. All of these have edge cases that pop up and ruin things at some point.

Using a status map

A better way to handle this is to use a status map within Vuex (assuming Vuex is where you are making the API calls, as described in How to query your API using Vuex in your Vue application).

A status map is an object in your Vuex store that you use to keep metadata information about the data that you’ve loaded, the state of it, and any other information that you want to keep track of for it. By having a single source for this information, you’ll have a one stop location for all of your components to get updates on the current status of the data they care about. I’m going to show this with a loading status for the data, and an error status.

You can set this up in your Vuex state with:

state: {
  posts: [],
  users: [],
  status: {
      users: {
          loading: false,
          error: false
      },
      posts: {
          loading: false,
          error: false
      }
  }
},

You can then set statuses in a mutation, just like we would any dynamically loaded data. Here’s what that would look like for the users state:

mutations: {
  SAVE_USERS(state, users) {
    state.users = users;
  },
  SAVE_LOADING(state, dataName, status) {
    // create a property in status
    state.status[dataName].loading = status;
  },
  SAVE_ERROR(state, dataName, status) {
    // create a property in status
    state.status[dataName].error = status;
  }
},

actions: {
  loadUsers({commit}) {
    commit('SAVE_STATUS', 'users', true);
    Vue.axios.get('users').then(result => {
      commit('SAVE_USERS', result.data);
      commit('SAVE_STATUS', 'users', false);
    }).catch(error => {
      commit('SAVE_ERROR', 'users', true);
      commit('SAVE_STATUS', 'users', false);
      throw new Error(`API ${error}`);
    });
  }
}

With these statuses set, we can now use them in our component. If we have a component that uses users and posts, for example, we could add this if to the loader:

<div v-if="$store.state.status.users.loading || $store.state.status.posts.loading">
  <img src="./../assets/loading icon.png">
</div>
<table class="users" v-else>
  <!-- data display once the data is loaded -->
</table>

The above will only show the table once the users and posts loading statuses are both false. And you can set up the same sort of logic for showing an error status as well.

This way of handling statuses are something I found by looking at how Vue Apollo handles loading state and realized that the same thing could be used for Vuex as well. It makes is super easy for a component to watch for the data that it cares about only.

Try this out and see if it doesn’t make handling loading states a lot easier.