💡 Vue Typescript State Management : We can do better than “isLoading” in 2022

Julien - Jan 4 '22 - - Dev Community

Sorry for the clickbait title, but I needed your attention 👀 

Have you ever encountered code like this one :

new Vue({
  el: '#app',
  data () {
    return {
      info: null,
      loading: true,
      errored: false
    }
  },
  filters: {
    currencydecimal (value) {
      return value.toFixed(2)
    }
  },
  mounted () {
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => {
        this.info = response.data.bpi
      })
      .catch(error => {
        console.log(error)
        this.errored = true
      })
      .finally(() => this.loading = false)
  }
})

...

<div id="app">
  <h1>Bitcoin Price Index</h1>

  <section v-if="errored">
    <p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
  </section>

  <section v-else>
    <div v-if="loading">Loading...</div>

    <div
      v-else
      v-for="currency in info"
      class="currency"
    >
      {{ currency.description }}:
      <span class="lighten">
        <span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
      </span>
    </div>

  </section>
</div>
Enter fullscreen mode Exit fullscreen mode

It’s an example I found in the Vue documentation here https://vuejs.org/v2/cookbook/using-axios-to-consume-apis.html#Dealing-with-Errors

What if you have multiple things that could load, do you add a loading2 variable ? đź‘€

To solve this issue, you can use a variable for each async actions you have with this 4 “states” :

  • IDLE : the user didn’t trigger the action yet
  • WAITING : the action is ongoing
  • ERROR : there was an error
  • DONE : The action succeeded

Using an enum with the different states, and better naming, the code can be rewritten like this :

enum AsyncState {
  IDLE = 'IDLE',
  WAITING = 'WAITING',
  ERROR = 'ERROR',
  DONE = 'DONE',
}

new Vue({
  el: '#app',
  data () {
    return {
      info: null,

      AsyncState,
      currentPriceLoadState: AsyncState.WAITING,
    }
  },
  filters: {
    currencydecimal (value) {
      return value.toFixed(2)
    }
  },
  mounted () {
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => {
        this.info = response.data.bpi
        this.currentPriceLoadState = AsyncState.DONE
      })
      .catch(error => {
        console.log(error)
        this.currentPriceLoadState = AsyncState.ERROR
      })
  }
})

...

<div id="app">
  <h1>Bitcoin Price Index</h1>

  <div v-if="currentPriceLoadState === AsyncState.WAITING">Loading...</div>
  <section v-else-if="currentPriceLoadState === AsyncState.ERROR">
    <p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
  </section>

  <section v-else>
    <div v-for="currency in info" class="currency">
      {{ currency.description }}:
      <span class="lighten">
        <span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }}
      </span>
    </div>

  </section>
</div>
Enter fullscreen mode Exit fullscreen mode

With better naming and this simple enum, you can almost cover all the use cases where you need to load one or multiple things and manage errors ✨

If you want to manage different error messages, you can add another variable with an enum type like this :

enum CurrentPriceLoadErrors {
  INVALID_CURRENCY = 'INVALID_CURRENCY',
  API_LIMIT_REACHED = 'API_LIMIT_REACHED',
  DEFAULT = 'DEFAULT',
}
Enter fullscreen mode Exit fullscreen mode

Tell me in the comment section if you like this trick or not, and if you have an even better technique !

And don’t forget to like and share this post if you liked it 💙

. . . . . . . . . . .
Terabox Video Player