
Beyond React 16 by Dan Ambramov – Async Rendering and React Suspense - timdorr
https://www.youtube.com/watch?v=v6iR3Zk4oDY
======
btown
So glad someone captured this talk!

At the 15 minute mark, he introduces a new paradigm for asynchronous IO
_within_ render functions; see a screenshot here:
[https://www.dropbox.com/s/wybqgtftuyqipk8/Screenshot%202018-...](https://www.dropbox.com/s/wybqgtftuyqipk8/Screenshot%202018-03-01%2009.41.11.png?dl=0).
This is groundbreaking, to say the least, as previously this needed to be done
by adding higher-order components to inject the result of the fetch as a prop
at some higher level; now, it's as simple as changing the src property in a
single line of code.

One of Dan's colleagues, Andrew Clark, described how this is implemented on
Twitter:
[https://twitter.com/acdlite/status/969171217356746752](https://twitter.com/acdlite/status/969171217356746752)

    
    
        Here's how suspending works:
        - in the render method, read a value from the cache.
        - if the value is already cached, the render continues like normal
        - if the value is not already cached, the cache *throws a promise*
        - when the promise resolves, React retries where it left off
    

Digging into the source code released in this companion tweet,
imageFetcher.read() indeed throws (instead of an exception) a Promise that is
apparently caught by React's new error handling infrastructure and handled
somewhere up the chain.
[https://github.com/facebook/react/blob/master/packages/simpl...](https://github.com/facebook/react/blob/master/packages/simple-
cache-provider/src/SimpleCacheProvider.js#L187)

The talk indicated that there will be tons of support for granularly choosing
when/how to show spinners, allowing interactivity with the rest of the
interface, etc. while this loading is ongoing.

It's a bit magical, but promising to say the least!

~~~
bajablast
So I am guessing if a prop is `instanceof Promise` or some other constructor
then it must trigger this response . . . is that correct?

~~~
btown
React isn't changing any logic of the types of props; if you actually pass a
Promise as a prop, it will be treated 100% as it was in previous React
versions.

What's happening instead is that imageFetcher.read() either returns a string
OR _throws_ a promise; it never _returns_ a Promise.

So <Component foo={fooFetcher.read(...)} /> either gets instantiated with the
fetched Foo, or throws so React.createElement(Component, ...) never gets
called in the first place.

Only if you physically _throw_ a Promise (or "thenable") does the new logic
apply:
[https://github.com/facebook/react/pull/12279/files#diff-1996...](https://github.com/facebook/react/pull/12279/files#diff-1996f2b11f9c68c0a81652e32be88ddbR132)
is called inside an exception handler.

~~~
pault
Wow, I never would have considered throwing anything other than an Error. On
the face of it, this seems like an incredibly powerful technique, but is it an
abuse of a language feature?

~~~
btown
Python “abuses” exceptions in a similar way every time you iterate over a
generator:
[https://softwareengineering.stackexchange.com/questions/1124...](https://softwareengineering.stackexchange.com/questions/112463/why-
do-iterators-in-python-raise-an-exception)

At the end of the day it’s just a control flow mechanism. And theoretically,
if you lack data needed to render, it’s an exceptional condition.

~~~
pault
It's a very interesting technique; I will definitely be keeping an eye out for
appropriate use cases.

------
swyx
typo in the title - its Abramov not Ambramov

It's interesting that Lin Clark basically demoed Time Slicing a -year- ago at
ReactConf:
[https://www.youtube.com/watch?v=ZCuYPiUIONs](https://www.youtube.com/watch?v=ZCuYPiUIONs)
and in the first 10 mins of Dan's talk you see basically the same thing with
user interaction applied.

createFetcher is brand new and here's the metaconversation on Twitter/Github:
[https://twitter.com/acdlite/status/969168681644179456](https://twitter.com/acdlite/status/969168681644179456)
and
[https://github.com/facebook/react/pull/12279/files#diff-50d8...](https://github.com/facebook/react/pull/12279/files#diff-50d8f0a9fb4af9baa0c2d4b8905567a7)

with a couple implementations here
([https://twitter.com/jamiebuilds/status/969169357094842368](https://twitter.com/jamiebuilds/status/969169357094842368))
and here
([https://twitter.com/actualhypercrab/status/94131894239559680...](https://twitter.com/actualhypercrab/status/941318942395596801))

// style discussion below

one thing I really appreciate about this talk is hard it is to even
communicate asynchronous problems and the solutions to them. Personally the
lagging animationFrame clock display (for time slicing) and the loading state
devtools (for "react suspense") were actually the bigger "wow" moments. (Yes I
know this talk is not about the tools or the charts)

he does another thing I'm a fan of - starting with a question. this helps
frame the rest of the talk: explaining why the question is a big deal,
breaking the question down, proposing some solutions, showing how the
solutions answer the question.

bottom line - there's more to learn from this talk than _just_ React.

~~~
acemarke
Yep, nice link roundup - beat me to it :)

Also see the summary post on the React blog for the key takeaways from the
demo:

[https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-
react-...](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-
react-16.html)

~~~
drudru11
Thanks for the link.

But boy, the Apple presentation style is so heavy in that blog post. "We call
this...", "We can't wait..."

~~~
spicyj
Sorry if the tone was a bit much! I figured it would be helpful to establish
common terminology that people can refer to, and I'm serious about our
excitement here – not exaggerating.

------
Klathmon
I express how excited I am for async rendering.

In my experience React has had 2 major paint points. async anything, and
styling. And this fixes the former, and I'd argue that the latter isn't
necessarily their job to fix.

Also, to have done this in a way that keeps a LOT of backwards compatibility
is amazing.

~~~
jefflombardjr
What do you think is so painful about styling in React? Genuinely curious. The
scoping of stuff? The organization?

~~~
Klathmon
There are basically 3 options, and they all have really big downsides:

* CSS modules - can use any CSS preprocessors, fast, can be extracted into CSS files, but it's very hard to "theme" and very hard to style/modify 3rd party components.

* Css-in-js - uses Js to render, using preprocessors is much more difficult, can't easily extract into CSS files, somewhat easier to theme and share.

* Inline styles - even slower, harder to preprocess, harder to extract, but very easy to theme and override.

And all 3 don't work well with one another. So if you get a widget made with
inline styles, overriding the color is hard with CSS modules...

~~~
bsimpson
Isn't the whole point of CSS-in-JS that you don't need a toy language to do
preprocessing if you have a real language like JavaScript?

I haven't really used SASS et. al., but my understanding is that they were
hacks to get shared constants, functions, and derived values in a CSS that
predated custom properties.

~~~
Klathmon
But with the downside of basically replicating a lot of what the CSS engine
does in Javascript, further polluting the already stressed "main" thread in
many JS applications. And doing it in a slower, less battery efficient, and
less cacheable way.

And in my opinion, a language like SASS isn't a "hack" but is a very specific
and extremely powerful language which is dedicated to one use (styling) and
therefore most styling-specific code is very natural with SASS, however with
JS it gets more difficult (want to extend another style defined elsewhere? You
kind of need to work with JS that wasn't really designed to make that an easy
task, in SASS it's `@extend %other-class`)

------
spicyj
FYI: A higher quality version of this video is on the React blog at
[https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-
react-...](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-
react-16.html).

~~~
bsimpson
I certainly understand the bias to host it on your own infrastructure, but I
really appreciate that I can download from YouTube for offline viewing on the
metro. Couldn't find a way to do that with the official version.

~~~
spicyj
That's really helpful to know for the future, thanks! We didn't have a strong
preference so ended up with FB.

------
sktrdie
So if I understand it correctly, anything after this line inside the render...

    
    
        const movie = movieDeatailsFetch.read(props.id);
        ...
    

... will block rendering and will defer to a parent <Placeholder /> component
to render instead?

Interesting magic I'd say, since I wouldn't expect such a line to block my
rendering.

Wouldn't it be a more "React way" to have HOC component or a render prop that
would work exactly like this .read() API?

    
    
       <MovieDetailsFetcher>
         {movie => <MovieDetails movie={movie} /> }
       ...
    

Then this HOC component doesn't need to have the IO-logic in the render, it
can put it in the `componentWillMount` or inside another lifecycle method of
React.

What's the advantage of putting the IO operation in the render instead of
inside a lifecycle method?

Also, how's race-conditioning done? Does the fetcher library have the logic to
only render the last fetcher, or is it more complicated than that?

There's lots of magic, especially in the IO part, and would've loved if he
went more into detail on how it's actually done - it's a JS-conf afterall.

Also, a fetch()-promise-based API is not the only type of IO-interface we
have. In fact it's only one of many.

HTTP2 for instance is on the horizon offering more complex interfaces with
open connections possibly returning several results like websockets - on the
other hand a Promise only returns one result and then dies. Observables might
be a more interesting abstraction for IO-kind of things.

Also, testing this seems rather complex since the render is effectively doing
a side-effect.

In any case, cool lateral thinking and I love hearing these type of talks
about cool new futuristic stuff rather than some boring old thing everybody
knows about.

~~~
danabramov
>will block rendering and will defer to a parent <Placeholder /> component to
render instead?

Yes, but only after the delay period passes. Before that, nothing will happen
on the screen (at least not until I add an inline spinner as one of the last
steps). Preventing a spinner from appearing and instantly disappearing on fast
connections is exactly what this feature enables.

>Interesting magic I'd say, since I wouldn't expect such a line to block my
rendering.

It works by throwing a Promise (and React catches it and waits for it before
retrying rendering). So it’s not really magic, just an unfamiliar pattern.
Conceptually this is similar to algebraic effects in languages that have them.

>Wouldn't it be a more "React way" to have HOC component or a render prop that
would work exactly like this .read() API?

No. If you watch the demo closely you’ll notice we _don’t_ show the spinner if
the load is fast enough. React prevents updating the whole tree. This is
impossible to express with a HOC without reimplementing the whole React in it.

>There's lots of magic, especially in the IO part, and would've loved if he
went more into detail on how it's actually done - it's a JS-conf afterall.

As I said earlier the actual mechanism is quite straightforward. We throw and
later React retries.

We’ll be posting an RFC with details. But for now we felt it was important to
_motivate_ this work, and even the motivation barely fit into 30 minutes.

>Observables might be a more interesting abstraction for IO-kind of things.

The core purpose of this feature is to suspend rendering until data is ready
to avoid flicker and things jumping around. You can use observables in your
code but I’d argue that, save for a few use cases, having components jump
around as new items “come in” is a janky experience. You can always build a
Promise interface that coalesces those observable updates into Promises of a
final list before rendering.

>Also, testing this seems rather complex since the render is effectively doing
a side-effect.

I actually think testing will get easier because now you can wrap your tree
with a fake cache in tests. Then even components that do data fetching won’t
attempt to reach the real network.

>Also, how's race-conditioning done? Does the fetcher library have the logic
to only render the last fetcher, or is it more complicated than that?

The fetcher library doesn’t have much logic. It’s basically a cache backed by
two Maps (for pending and resolved data).

React just retries rendering after Promise has resolved (or re-render happened
due to another reason, like prop change). So there is no need for explicit
logic handling race conditions. Instead of keeping continuations “in flight”
we just abort rendering and retry when data is ready. So there’s nothing to
race for.

~~~
just-boris
Thank you! I appreciate all your replies, but want clarify this one:

> This is impossible to express with a HOC without reimplementing the whole
> React in it.

What is the problem here? We return `null` from the beginning, then spinner,
if reached timeout and finally, the provided component, if data has arrived.

~~~
danabramov
Please watch my demo. It doesn’t just unmount the children when I start
fetching. It keeps the _previous_ screen in place (and fully interactive)
while the new screen is loaded. If the new screen is ready fast enough, then
it fully replaces the old screen without any intermediate state (empty or
loading).

I know it’s a bit hard to believe because none of JS libraries I’m aware of
can do this yet. But that’s what it does thanks to cooperative scheduling and
a double buffering-like system we implemented. I totally understand that it
doesn’t quite “click” from the first explanation because you really need to
try it to get it.

But to explain it again: React doesn’t _remove_ the child tree, it _suspends
the whole update_ from committing before the tree is ready. So there’s no
“holes” or “spinners” if it loads fast enough.

Intuitively my last example with Img component may help. There’s no a way a
leaf Img component could delay the whole page from rendering before. With
suspense it is possible.

------
aappddeevv
I think my only concern for throwing a Promise to do a non-local goto and
cause the scheduler to delay rendering that component is whether the thrown
Promise can be caught by mis-behaving code that makes it difficult to debug
what's going on. It would be nice to have a more line-of-sight API as well vs
only an exception based model.

------
crudbug
Is there plan to implement the react-core in C or other native language ?

I can see that being compiled to webassembly for browsers and react-native can
have multiple language support ?

~~~
acemarke
No, there's no plans to rewrite the React core in C, Rust, Reason, WASM, or
anything else right now.

Lin Clark, who works for Mozilla, gave a talk on "What WebAssembly Means for
React" last year (
[https://www.youtube.com/watch?v=3GHJ4cbxsVQ](https://www.youtube.com/watch?v=3GHJ4cbxsVQ)
). In a recent Twitter thread, she said that some more useful WASM pieces are
in the works, but still not likely to be a big improvement or worth the effort
to rewrite React (
[https://twitter.com/linclark/status/967860936550879232](https://twitter.com/linclark/status/967860936550879232)
).

~~~
yazaddaruvala
It would be really interesting to one day have React be a polyfill for an in-
browser async DOM renderer.

Is that in (very, very, long-term) consideration?

~~~
danabramov
I think my talk paints a relatively convincing picture why DOM nodes aren’t a
sufficient primitive if you care about the features I described, as you’d need
something like React to orchestrate those updates.

~~~
crudbug
Hello Dan,

Great talk ! My thinking behind the top statement was with a native
implementation of react-core, the react-native story becomes more compelling
with JSX(ish) UI templates / CSS Styles and multi language business logic
support.

Once you have this, the browser becomes another target. I see Flexbox
implementation is already native with Yoga [0].

[0] [https://yogalayout.com/](https://yogalayout.com/)

------
ty___ler
I’m pretty excited to see how the api could interop with some new native
features of js, like for ex async class functions are now possible and I bet a
setup like this could remove a lot of IO overhead in the future

    
    
      class Test {
        async render() {}
      }
    

Kind of hard to come up with a concrete use-case with how little we know about
the new features. Still super interesting though!

~~~
alexeyraspopov
Interop with language feature is definitely a thing. It helps people to
understand a tool without the need of digging into implementation details,
since those details are language features that developers already familiar
with.

There is a way to do this kind of things with current React version (16.2):
[https://github.com/alexeyraspopov/react-
coroutine](https://github.com/alexeyraspopov/react-coroutine)

You can use generators, async functions, and even more, async generators.
Worth checking examples in the repo.

~~~
ty___ler
Nice, awesome work!

------
solidr53
I did a little demo of working with the new Suspense API.

[https://github.com/birkir/react-suspense-
demo/blob/master/sr...](https://github.com/birkir/react-suspense-
demo/blob/master/src/App.js)

------
anotherfounder
This is pretty amazing, kudos to the React team! Just hope that SSR isn't an
afterthought with this feature. That is probably been my only little grouse
with the React team that SSR compatibility is always a 'Not sure, someone
should try it' response.

~~~
anotherfounder
I guess another question I have is how does the React or the Redux team see
this playing with Redux. Dispatch returns promises but then the cache is the
redux store itself - so would the fetcher read from the store possibly?

~~~
acemarke
I'm a Redux maintainer (as is Tim Dorr, who submitted the post).

Use of promises with dispatching is, as far as I can see, not relevant to this
particular discussion. It seems that the caching aspect is up to you - the
important thing is that if a component decides it needs to wait for data
before it resumes rendering, it needs to throw a promise.

What _is_ relevant is figuring out how to synchronize dispatched actions that
cause updates to the Redux store with React possibly pausing a given component
tree re-render cycle, applying a different update, and then resuming the rest
of the original update. We've had some initial discussions, and are still
trying to grasp what the impacts are here.

Ultimately, it's possible there will be internal changes to the React-Redux
library - we just don't know what those changes will be yet. But, if there
are, we'll do our best to keep the public API stable.

------
hemantv
Maybe a dumb question or wrong forum. But how do you start using latest React
in a project?

~~~
oblosys
Npm has alpha versions react@16.4.0-alpha.0911da3 and react-
dom@16.4.0-alpha.0911da3 you can experiment with.

~~~
danabramov
there be bugs

