I have mixed feelings about this. In a language with proper enums like Rust this is certainly the way to go, because your entire data structure can be tied to which state you're in (Success would <i>only</i> contain the position, Rejected would <i>only</i> (and always) contain an error, Loading would <i>never</i> contain redundant data). In Rust you would also get the benefit of having match { } make sure you always take care of every possible variant.<p>In JavaScript, on the other hand, code could just as easily set an error and forget to set the status as set an error and forget to clear the position. There's still some overlap between state info and there's not a singular, clear winner between the two patterns.<p>Here's what I would do for this case: first, move the error rendering clause above the position one. Erroring, like loading, is an exceptional status above the "normal" status. Therefore the position should be the "fallthrough" branch. This change alone would fix the actual problem demonstrated.<p>Then, to help avoid inconsistencies, I like to put my "isLoading: false" in a "finally" clause (if it's on a Promise), or some equivalent. Unfortunately watchPosition is a bespoke function with regular callbacks instead of a promise, but you could still centralize the loading flag clearing in some way. Or maybe "promisify" that function with a new Promise((res, rej) => {}).<p>Certainly if you have more than just these three statuses you start getting into territory where a status string makes more and more sense. However, these three (success, error, loading) are special, and in a large number of cases they're all you have, so they can be afforded some special treatment.
At this point I'm starting to think that every state framework should ship with something like Diode's Pot[0] (which this post also reimplements, though with more strings and without the clear state diagram).<p>[0]: <a href="https://diode.suzaku.io/advanced/Pot.html" rel="nofollow">https://diode.suzaku.io/advanced/Pot.html</a>