16
💡 Vue Typescript State Management : We can do better than “isLoading” in 2022
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>
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>
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',
}
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 💙
16