Basically, React Suspense
My "basically" projects aim to take fascinating concepts and break them down into more "basic"/bite-size versions. This project highlights React's suspense for data fetching functionality, creating a minimal example that doesn't even use React, but mimics its behavior in a basic sense.
⚠️Disclaimer: I do not work on React core at all and this is a huge guess. I have not extensively looked at the source code of this feature and I don't really know what I'm doing, so please take this with a grain of salt and refer to the React core team for offical things. This repo here is my personal exploration to learn these things publicly (thanks, @sw-yx). I might have gotten it either partially or completely wrong. In this case, hopefully someone will gently correct me if things are not quite right and help me figure out the "truth"/the right way this works.
Take a look at index.js to see how (I think) it works. We have:
- a central cache
- a "resource creator"
- some "components" that fetch things using a resource
- finally, the "core" that ties it all together.
I kind of accidentally wrote this while researching/learning about algebraic effects. I've heard a lot of this terminology around React's shiny new (and still experimental!) Concurrent Mode and so I wondered how it fit in. Turns out this might be how.
¯\_(ツ)_/¯. I think this is really novel because algebraic effects allow code to behave in a synchronous way while still preserving asynchronous functionality, pausing, performing an effect, and resuming where necessary.
await allows similar behavior, but any function automatically returns a
Promise when prepended with the
async keyword, which kinda sorta "contaminates" it, and potentially leads to a special kind of async hell when we want to do something synchronous.
With algebraic effects, functions can be synchronous while allowing an external async effect handler to deal with the async part. The cool thing about this is the handler could be swapped out for pretty much anything centrally, and "user code" stays exactly the same.
Another benefit is that it literally "defers" to an effect handler higher in scope. I think the best analogy for algebraic effects is
try/catch blocks. No matter where the code comes from that is enclosed in
catch handler in a different scope/context/file(!) is fired and can handle exceptions from literally anywhere. This is quite cool. Applied to data fetching, one can
try to use data that might be available. If it's not available, the exception (or effect handler) of "I have no data" is caught wherever we have a handler and it is processed accordingly.
If you'd like to have a chat or discuss things more, or even request more explainer-type things, @ me on twitter.