News for hackers. Stuff that matters.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by btown on Thursday March 01, 2018 @12:35PM (#16494156)
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-.... 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

    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...

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!

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by pault on Thursday March 01, 2018 @03:45PM (#16496129)
The description of suspending sounds exactly like yielding generators and/or async await; why not build this feature on top of existing language constructs? I am quite sure the react core team has put more than the 30 seconds of thought I have into this question, so I'm curious what their reasoning is for using this implementation.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by abiodun00 on Thursday March 01, 2018 @06:23PM (#16497345)
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by pault on Thursday March 01, 2018 @06:34PM (#16497409)
That's a great thread, thanks for the link!
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by acjohnson55 on Friday March 02, 2018 @01:22PM (#16504255)
This seems to me like a workaround for the fact that React requires `render` methods to return React elements. And I suppose it also takes advantage of the fact that the `read` method can `throw` its way out of your `render` function, obviating the need to check its result and manually `return`. But not gonna lie, I'm pretty suspicious of overreliance on creative use of `throw`ing as something that is going to cross through application code's control flow. But perhaps it will prove convenient enough to be worth it.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by bajablast on Thursday March 01, 2018 @01:38PM (#16494773)
So I am guessing if a prop is `instanceof Promise` or some other constructor then it must trigger this response . . . is that correct?
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by btown on Thursday March 01, 2018 @02:28PM (#16495296)
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... is called inside an exception handler.

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by pault on Thursday March 01, 2018 @03:38PM (#16496036)
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?
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by riquito on Thursday March 01, 2018 @03:51PM (#16496194)
Is a feature of the exceptions to let you handle exceptional cases far away from the caller, up in the stack.

You should keep a distinction between exceptions that means "error" and exceptions that means "some kind of event happened", and handle them accordingly.

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by btown on Friday March 02, 2018 @01:19AM (#16499526)
Python “abuses” exceptions in a similar way every time you iterate over a generator: https://softwareengineering.stackexchange.com/questions/1124...

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.

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by pault on Saturday March 03, 2018 @02:46PM (#16511167)
It's a very interesting technique; I will definitely be keeping an eye out for appropriate use cases.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by acjohnson55 on Thursday March 01, 2018 @11:17PM (#16498973)
My guess is that it won't catch on in the long run. But, you never know.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by acemarke on Thursday March 01, 2018 @01:51PM (#16494905)
The key phrase is "thenable", which is a term for anything where `typeof variable.then === "function"` is true.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by wereHamster on Thursday March 01, 2018 @02:10PM (#16495111)
But only when passed to HTML elements I hope. Because say I have my own type of the shape `{ then(): Whatever }` and try to pass that as a prop to one of my components I don't want React to invoke that function.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by acemarke on Thursday March 01, 2018 @02:17PM (#16495182)
It's not about passing props - the "thenable" detection comes into play if you throw a promise (or something shaped like a promise) from within `render()`.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by wereHamster on Thursday March 01, 2018 @02:39PM (#16495415)
Wait, can render functions now throw, legally?
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by timdorr on Thursday March 01, 2018 @02:48PM (#16495490)
Yup. This builds on error boundaries and componentDidCatch: https://reactjs.org/blog/2017/07/26/error-handling-in-react-...
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by danabramov on Thursday March 01, 2018 @02:49PM (#16495507)
Yes. (For this use case.)
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by bsimpson on Friday March 02, 2018 @01:44AM (#16499618)
> throws a promise

> ...

> It's...promising to say the least!

^ this guy :finger_guns:

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by ocfx on Thursday March 01, 2018 @03:01PM (#16495644)
Is the cache global?
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by danabramov on Thursday March 01, 2018 @03:16PM (#16495792)
It's up to you. I intentionally kept moving parts to the minimum in my demo, but here's the real thing I was using behind the scenes: https://github.com/facebook/react/tree/master/packages/simpl.... So in that sense it's not global, you can create as many as you like and then isolate them (e.g. per subtree).

The `simple-cache-provider` is just a reference implementation though. It's somewhat naïve, e.g. it doesn't have invalidation strategy and just lets you replace the whole cache with a new one if you want to invalidate.

We'll publish more details on lower level API and how to write your own cache in the future.

Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by btown on Thursday March 01, 2018 @03:18PM (#16495824)
It seems from https://github.com/facebook/react/blob/master/packages/simpl... that in the live version you'll be specifying which cache to use; this could be global, provided via React's old or new Context APIs, or passed down through props. And you could always write your own fetcher factory if you want to do something really custom; there's nothing special about the SimpleCacheProvider, and it doesn't use any React internals.
Re:Beyond React 16 by Dan Ambramov – Async Rendering and Rea... by danabramov on Thursday March 01, 2018 @03:45PM (#16496133)
FWIW my demo code looked like

    export let cache;
    function initCache() {
      cache = createCache(initCache);
    }
    initCache();

    export function createFetcher(fetch) {
      const res = createResource(fetch);
      return {
        read(...args) {
          return res(cache, ...args);
        },
      };
    }