I find myself adding such a data-structure on all of my projects, so that my React component states can hold some request current status:
type 'a t =
| NotAsked
| Loading
| Done 'a
val mapU: 'a t -> ('a -> 'b [@bs]) -> 'b t
val map: 'a t -> ('a -> 'b) -> 'b t
val flatMapU: 'a t -> ('a -> 'b t [@bs]) -> 'b t
val flatMap: 'a t -> ('a -> 'b t) -> 'b t
val getWithDefault: 'a t -> 'a -> 'a
val isLoading: 'a t -> bool
val isDone: 'a t -> bool
val isNotAsked: 'a t -> bool
val eqU : 'a t -> 'b t -> ('a -> 'b -> bool [@bs]) -> bool
val eq : 'a t -> 'b t -> ('a -> 'b -> bool) -> bool
val cmpU : 'a t -> 'b t -> ('a -> 'b -> int [@bs]) -> int
val cmp : 'a t -> 'b t -> ('a -> 'b -> int) -> int
Would you find it interesting to have that in Belt under a module named AsyncData or RemoteData (like Elm)?
Not sure types like this are not dependent on how things are done in your app. E.g., you might handle errors in the API (so that it never reaches your components), or you might want a Reloading of 'a variant, besides Loading. Having this module in a standard library is rather opinionated.
reloadData is actually never Done(_), so the type is a bit of a lie.
Not sure if I pattern matching on 2 variants reads better than on a single variant (but maybe it’s no big deal).
If I have to jump through hoops to customize the standard AsyncData, why not just roll my very own AsyncData. The set of helpers you propose are not that hard to write—and you’d probably have to write them for the state record anyway.
reloadData is actually never Done(_), so the type is a bit of a lie.
It could, if for instance you want to highlight the diff between the previous and new data
If I have to jump through hoops to customize the standard AsyncData, why not just roll my very own AsyncData. The set of helpers you propose are not that hard to write—and you’d probably have to write them for the state record anyway.
My idea would be to have that data-type a common building block that works as-is for the most common cases, can be shared across libraries, and allows you to build abstractions upon (e.g. reload, pagination…) with little work.
One option to allow wide reuse across libraries would be to use a polymorphic variant type instead of a normal variant. Then users could add more cases like `Reloading.
Btw, I’m guessing from the lack of canceled state here that you’re using a promise-like mechanism in your React component. In case you are: don’t forget to use a cancelable paradigm instead; otherwise it causes leaks and bugs.
Regarding this data type itself: like the above comments said, I also am not too sure about this extra wrapping when
Such loading itself is simple enough to be your own app’s little util
There’s differing opinions on what states to have and not have (I don’t think using poly variant cuts it here though, and yes, reloading makes these apis more misleading here and there).
It’s not much of a ROI vs having a dedicated variant inside your app.
The various data fetching libraries likely won’t build on top of this (but a product could), because it’s a little abstraction. They’ll likely just expose their own data type. Not much reuse for an extra indirection I think.
We also wanna encourage putting extra care into the UX, e.g. progress indicator and data-specific loading UX. This is a little bit much of a pull toward not doing those.
Yeah. I wanted to have a built in (so that it doesn’t make an extra dependency) way to represent requests status (mostly in React components), but if that seems inappropriate I’ll just release it on my own
That’s 3 wrapping and 2 concepts to express something that’s actually not too clear from reading and raises other questions (is cancelled an error? Does it count as done? Why does it look different? What other composition is there? etc).
But like Patrick said, just like for Elm’s RemoteData, I think we’re better having this in userland (at least for now).
This is very tricky to make part of a stdlib. Over the course of several projects I went through three iterations of the same variant and eventually ended up with a completely different design.
Being able to move on and learn from previous designs is a lot easier in your own software or a userland library.