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 shouldn't I use it? Then I read it. And saw his point.
It is a common practice to use isLoading boolean to show some placeholder or spinner when data in our app is loading. This is fine - you set isLoading to false, change it to true when data is loading and when data is here - put it back to false. But what happens when error occurs? Data is not loading but there is no data to show either. We start to add more conditions - first not loading and no error, then for not loading but with error, another one for loading. Do you see the point?
What Kent suggests in his approach is having status with different enum values for every case e.g. 'idle', 'resolved', 'rejected'. In the code then we can go like (examples based on the article that I mentioned earlier):
if (status === 'idle') {
return <div>Data is loading...</div>
}
if (status === 'resolved') {
return <div>{Fetched data}</div>
}
if (status === 'rejected') {
return <div>Something went wrong!</div>
}
Thanks to that we can set status for particular case after every activity and there is no need for double conditions (like is not loading and there is no errors etc).
To get rid of equal signs we can put status info in variables.
const isLoading = status === 'idle';
if (isLoading) {
return <div>Data is loading...</div>
}
And that's it! I recommend reading Kent's article for deeper explanation and more examples.
Oldest comments (43)
Very interesting, I'll definitely use that pattern! Thanks for sharing! 👍
Nice tip. And if needed you could implement a state machine.
Thanks! Yes, that's true. But state machine would be work for better more complex status management
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-.... 😉
thanks! I will check out your articles
Agreed, a state machine in this case would be overkill. Compare time and mental load to
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
You can create an Enum type for those status
Good tip! Thanks :)
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!
Yes, when you first hear about it is sounds strange but then you realise it really makes sense.
Enum also helps in expanding the feature more in the future if the need arise. Make things more cleaner and easier to read!!
Hi, how would you implement enum over here?
I'm definining my state types as :
and giving me type safety. Are you talking about making StatusEnum?
I use same pattern, but I use "busy" instead of "idle" and "idle" is use when promise/fetch or another isn't launched yet.
The best way of clean code and well structured
Thats great, thanks for sharing
Good idea! TypeScript’s Enums could also do the job here 🔥
You could also wrap fetch logic in a hook that returns { data, loading, error }.
And then:
Nice one!
Yeah! That is also my approach!
I have this habit of writing
It is probably over-cautious, but checking for null and undefined is nice - these errors can be really hard to debug otherwise.
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?I think you are actually right!! 😮 I always thought this was only a check for null.
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 😅
You did miss something.
This is not true when it short-circuits. That is, when the left hand side is falsy.
No, they won't
In the end,
undefinedwill cause errors,nullwon't.falsedepends 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:Why? Now you don't need to think about all falsy values and the rendering never breaks :D
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?
!!value is effectively the same as
Boolean(value)and will therefore always returnfalsein the case of all falsy values.Will always resolve to
falseif 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 seeingBoolean(...), that's less likely.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 😊👍
The _callable Global Objects are a gem ✨.
I also recommend
Number(value)over the obscure+value, which both are usually better to "type-cast" thanparseIntorparseFloat, as it will properly fail when thevalueisn't representing a number, instead of doing something unexpected.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 😊
this is my everyday use. No status required.
I like that React-query allows for that approach and it works excellently in JS and in TS.