Futures: Making queries composable (mapping, combining) #8660
Unanswered
GiacoCorsiglia
asked this question in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
First: fantastic library with super thorough documentation, thank you :)
I'm curious if thought has been given to formalizing the
UseQueryResult
as The Way to represent async state in React/rendering libraries in general. For now, let's call this type aFuture
and explore some (I think) useful things we can do. I've used something like this successfully in two separate professional projects.The minimal definition of a
Future
might look something like this:This is compatible with both TanStack Query and also SWR. Of course, the real version would need to give thought to the other properties on
UseQueryResult
(likely,UseQueryResult
extendsFuture
with extra properties). It might also be nice to make this a discriminated union somehow.There are (at least) 3 useful things we can do with this.
mapFuture
: transforming query resultsmapFuture
is likePromise#then
for aFuture
. A simplistic version looks like this:This lets you transform the result of your query on the client while preserving the loading state. For example:
Sure, you can totally do this in all the components that call
useProducts
, once they have checked ifproducts.data
has loaded, but I would rather encapsulate that in theuseProducts
hook.mapFuture
can be extended to allow transforming theerror
, too, similar to howPromise#then
supports a second argument that works likePromise#catch
.I think
mapFuture
makes theFuture
type a "Functor".Maybe
mapFuture
is implemented as a method onFuture
instead (i.e.,products.map()
instead ofmapFuture(products)
).combineFutures
: LikePromise.all
for Futures.You can merge the results of multiple queries in arbitrary ways using
combineFutures
.This is similar to, but not the same as,
useQueries()
, which supports acombine
argument. The benefit of having a separate function is that things compose more cleanly. For example,I'm sure there is a functional programming term for
combineFutures
.Creating a
Future
withoutuseQuery()
.Occasionally, there are scenarios where you have async state but don't want or need
useQuery()
. This is why it's useful to have a standaloneFuture
concept—outside ofUseQueryResult
. For example:You can compose this with other Futures (e.g., using
combineFutures
), some of which may have come fromuseQuery()
. Also, if you have implemented, for example, a component that shows a loading state when waiting for the result of auseQuery()
, you can use that same component to wait for the heavy library to load—because that component expects aFuture
.I would love to hear others' thoughts on this idea.
Beta Was this translation helpful? Give feedback.
All reactions