DEV Community

Status instead of isLoading boolean?

Joanna Otmianowska on April 26, 2021

When I saw the article 'Stop using isLoading boolean' written by Kent C. Dodds my first thought was - what's wrong with isLoading boolean? Why shou...
Collapse
 
matheusmurden profile image
Matheus Murden • Edited

You could also wrap fetch logic in a hook that returns { data, loading, error }.
And then:

loading && <Loading />
error && <Error />
data && <Data />
Enter fullscreen mode Exit fullscreen mode
Collapse
 
larsejaas profile image
Lars Ejaas

Yeah! That is also my approach!

I have this habit of writing

!!loading &&<Loading />
Enter fullscreen mode Exit fullscreen mode

It is probably over-cautious, but checking for null and undefined is nice - these errors can be really hard to debug otherwise.

Collapse
 
pclundaahl profile image
Patrick Charles-Lundaahl

What's the purpose of the !! here? The && will cast the left-hand operation to a boolean already. Won't null and undefined already be converted to false for the purpose of the guard clause?

Thread Thread
 
larsejaas profile image
Lars Ejaas

I think you are actually right!! 😮 I always thought this was only a check for null.

Thread Thread
 
pclundaahl profile image
Patrick Charles-Lundaahl

Ah okay! I wasn't sure if I'd missed something or not. I use guard clauses pretty extensively in my React code, but I also use quite a few languages across a bunch of projects. Wasn't sure if I'd gotten mixed up 😅

Thread Thread
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

You did miss something.

The && will cast the left-hand operation to a boolean already.

This is not true when it short-circuits. That is, when the left hand side is falsy.

Won't null and undefined already be converted to false for the purpose of the guard clause?

No, they won't

loading = undefined

loading && true
//=> undefined

loading = null

loading && true
//=> null
Enter fullscreen mode Exit fullscreen mode

In the end, undefined will cause errors, null won't. false depends on the renderer.

Side note! If you want to be explicit, using Boolean(loading) is probably more readable than double negation (!!loading).

The best way is to not rely on && (or ||) to return the right result, but use a ternary:

loading ? ... : null
Enter fullscreen mode Exit fullscreen mode

Why? Now you don't need to think about all falsy values and the rendering never breaks :D

Thread Thread
 
larsejaas profile image
Lars Ejaas

Nice writeup! I actually use the ternary a lot, but I do not find it useful for all purposes. I am a bit unsure!? So you are actually saying that the "!!" prefix would be needed here to "catch" all falsey values?

Thread Thread
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

!!value is effectively the same as Boolean(value) and will therefore always return false in the case of all falsy values.

!!value && <MyComponent />
Enter fullscreen mode Exit fullscreen mode

Will always resolve to false if the left hand side is falsy. False values are not rendered, so yes, that would catch all falsey values.

I still recommend Boolean(value) && <MyComponent /> over !!value && <MyComponent /> because it is both explicit and easier to read, albeit it a bit longer. It's easy to skip over !!, but more importantly, it's easy to forget to add !!. If you're used to seeing Boolean(...), that's less likely.

Thread Thread
 
larsejaas profile image
Lars Ejaas

That's actually a great point! I haven't used Boolean(..) in my code I think 🤔 But I like how it's more descriptive! Thanks for taking the time to responde 😊👍

Thread Thread
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

The _callable Global Objects are a gem ✨.

I also recommend Number(value) over the obscure +value, which both are usually better to "type-cast" than parseInt or parseFloat, as it will properly fail when the value isn't representing a number, instead of doing something unexpected.

Thread Thread
 
larsejaas profile image
Lars Ejaas

Ahh, cool. I haven't digged super deeply into the differences, I just really like "Number" because "it does what it says on the tin" 😆 I really like easy readable code 😊

Collapse
 
joannaotmianowska profile image
Joanna Otmianowska

Nice one!

Collapse
 
frozenbyte profile image
Frozen_byte

this is my everyday use. No status required.

Collapse
 
dgreene1 profile image
Dan Greene

I like that React-query allows for that approach and it works excellently in JS and in TS.

Collapse
 
aleksandrhovhannisyan profile image
Aleksandr Hovhannisyan

I actually ran into this situation at work recently and a colleague suggested using an enum instead of separate loader/status booleans. It definitely made things cleaner and the logic easier to follow!

Collapse
 
joannaotmianowska profile image
Joanna Otmianowska • Edited

Yes, when you first hear about it is sounds strange but then you realise it really makes sense.

Collapse
 
myleftshoe profile image
myleftshoe

Nice tip. And if needed you could implement a state machine.

Collapse
 
joannaotmianowska profile image
Joanna Otmianowska • Edited

Thanks! Yes, that's true. But state machine would be work for better more complex status management

Collapse
 
macsikora profile image
Pragmatic Maciej

Everything is a state machine, even isLoading state with setState represents such with two possible states. The problem starts when the model needs more than two states, then bool starts to be a problem. I have few articles about this subject, take this - dev.to/macsikora/boolean-the-good-.... 😉

Thread Thread
 
joannaotmianowska profile image
Joanna Otmianowska

thanks! I will check out your articles

Collapse
 
myleftshoe profile image
myleftshoe

Agreed, a state machine in this case would be overkill. Compare time and mental load to

  1. write out some if statements (virtually no mental load) vs
  2. think about representing the logic as a state machine, draw a state diagram, etc

Not only that but the code would be harder for others to grok than if statements and would make them wonder why it was implemented as a state machine - "I must be missing something"

And if you were a contractor, paid by the hour, using a state machine in this case would look like that you were milking your hours and using your time to experiment or hone your skills

Collapse
 
larsejaas profile image
Lars Ejaas

It might be great for some situations but more verbose for others...

Let me explain.

Normally (in React, but I guess it would be almost the same elsewhere) I would import the fetch logic like this:

const [isLoading, Data, isError, Error] = GetData(URL)

Then in the JSX:

{!!isLoading ?
(<div>Data is Loading</div>)
:
(!!isError?
(<div>Something went wrong</div>)
:
(<div>Data</div>)
)}
Enter fullscreen mode Exit fullscreen mode

My point is that the booleans make it possible to use really short syntax.

I definitely see your point when status could have a lot of different states, but if you have a lot of different skeleton loaders and stuff I think booleans are hard to beat.

why not return the different states like booleans?

something along the lines:

const [iddle, resolved, rejected] = GetData(URL)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
amiceli profile image
amiceli

I use same pattern, but I use "busy" instead of "idle" and "idle" is use when promise/fetch or another isn't launched yet.

Collapse
 
lucassperez profile image
Lucas Perez

This seems very nice!
Particularly, I like switch case. I think it works nicely when we have many ifs in a row comparing to a single value.
Of course there are many other great suggestions in the comments!

Collapse
 
sandromaglione profile image
Sandro Maglione

If you are into functional programming, this is the perfect situation for using a union-type. There are some great libraries in typescript to implement union-types. I am using @practical-fp/union-types, check it out!

github.com/practical-fp/union-types

Collapse
 
mrdulin profile image
official_dulin

If you don't want to add extra words - "idle"

Just consistent with the state of the JavaScript Promise.

A Promise is in one of these states:

pending: initial state, neither fulfilled nor rejected.
fulfilled: meaning that the operation was completed successfully.
rejected: meaning that the operation failed.

Collapse
 
sgolovine profile image
Sunny Golovine

This article makes me feel very (type) unsafe. But seriously, I would not recommend this route unless

  • You use Typescript
  • Store each status as an enum.

The big issue I have is the inevatable instance where you spell 'loadng' instead of 'loading' and your logic breaks. This can be avoided using union types in typescript of creating an enum with regular JS.

Collapse
 
maciekgrzybek profile image
Maciek Grzybek

That's why we should all move to TS :) oh and also I'd recommend union types instead of enums

Collapse
 
c5n8 profile image
c5n8

I made a package around this idea for Vue.
github.com/c5n8/vue-use-async-hook
The challenge is to name the state when we have not called the function for the first time. I call it standby, but I think it could be better.
Also, if only Javascript/Typescript has implicit member expression like Swift, we could eliminate these space hogging strings, masquerading as a pseudo enum.

Collapse
 
deepanjangh profile image
Deepanjan Ghosh

Enum also helps in expanding the feature more in the future if the need arise. Make things more cleaner and easier to read!!

Collapse
 
adarshaacharya profile image
Aadarsha Acharya 🚀

Hi, how would you implement enum over here?
I'm definining my state types as :

export interface AuthState {
  status: 'idle' | 'pending' | 'resolved' | 'rejected';
  isAuthenticated: boolean;
  error: string;
  user: User;
}
Enter fullscreen mode Exit fullscreen mode

and giving me type safety. Are you talking about making StatusEnum?

Collapse
 
asafagranat profile image
Asaf Limi Agranat • Edited

In my opinion you are over simplifying what in reality is mostly a complex matter. To begin with, you might be responsing to a particular article, but in your own standalone article you are not specifying what action you are performing for which you are calling the isLoading status in the first place. I can only infer you are refering to a fetch operation, given the scenrios you lay out. But isLoading is used in many different use cases that have multitude of scenarios of different complexities. You could be loading a new view, refreshing part of the UI, loading pre-fetched data, calculating post action etc. isLoading as boolean is very valid for those many scenarios, and does not correlate to response statuses.
Other than that, isLoading is self-indicative by its name, while the other statuses you exemplify are more abstract in meaning and require closely-coupled context to know how to use them. Self-indicating statuses are to be appreciated, even being boolean. The verbosity of having to check multiple statuses together in order to know how to act on them is not a bad thing, is not anti-pattern, and I'd even dare say they are desired. In the end of the day, we all just want clearly read code, especially when it's someone else's.

Collapse
 
joannaotmianowska profile image
Joanna Otmianowska

I am not saying that isLoading is always bad. I just wanted to share what I learnt in the article I mentioned. That is really interesting to me because earlier I really didn't even think that in some cases isLoading boolean may be not the best choice

Collapse
 
mathieuhuot profile image
Mathieu Huot

Very interesting, I'll definitely use that pattern! Thanks for sharing! 👍

Collapse
 
fatehmohamed14 profile image
Fateh Mohamed 🐢

You can create an Enum type for those status

Collapse
 
joannaotmianowska profile image
Joanna Otmianowska

Good tip! Thanks :)

Collapse
 
shubhamb profile image
Shubham_Baghel

The best way of clean code and well structured

Collapse
 
tojacob profile image
Jacob Samuel G. • Edited

In Typescript I always use enums for that :)

Collapse
 
aryangomes profile image
Aryan Gomes

Thanks for the tip and for sharing!

Collapse
 
rohithv07 profile image
Rohith V

Thats great, thanks for sharing

Collapse
 
kaspermroz profile image
Kasper Mróz

Good idea! TypeScript’s Enums could also do the job here 🔥

Collapse
 
andrewbaisden profile image
Andrew Baisden

Good tip this is a great way to deal with it.

Collapse
 
jochemstoel profile image
Jochem Stoel

It is my opinion that every developer who implements a Boolean isLoading is not a competent developer.