
Update on Async Rendering - runesoerensen
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
======
bhj
> 17.0: Remove componentWillMount, componentWillReceiveProps, and
> componentWillUpdate . (Only the new “UNSAFE_” lifecycle names will work from
> this point forward.)

Wow, I try to use those as little as possible because there's always a bit of
a smell, but I suspect there's a lot of code out there that will be getting a
second look now. Kudos to the React team for explaining the rationale and
migration path(s) in detail. React has consistently made me write better code,
however begrudgingly.

~~~
Blackstone4
When I first started using React, I kept trying to use componentWillMount,
componentWillReceiveProps, and componentWillUpdate... I kept getting stuck in
infinite loops... new prop updates state which re-renders the component which
means "new props" updates state which re-renders component etc. Or something
like that....

Now my react components are a lot simpler and I don't try anything fancy. The
parents tend to handle the data fetching and they pass it down to the children
components which are often stateless components. So I only use
constructor(props) and render() plus custom functions. It keeps it cleaner but
I also have more components as a result. Some of which do very little.

So I agree, those functions smell and looked more useful upon first glance
than they actually were.

~~~
k__
I used them mostly for server side rendering, if I remeber correctly.

componentDidMount will fire only on the client and componentWillMount on
client and server.

Since the server rendered stuff wasn't interactive I could only do a subset of
the things the client allowed, so I would do these in componentWillMount and
the rest in componentDidMount only on the client.

~~~
danabramov
If there’s some specific use case we’re missing in the blog post please let us
know!

`componentWillMount` is technically equivalent to the constructor so there's
nothing you could do on the server you couldn't do in the constructor instead.

[https://reactjs.org/blog/2018/03/27/update-on-async-
renderin...](https://reactjs.org/blog/2018/03/27/update-on-async-
rendering.html#other-scenarios)

~~~
k__
I know, but I often avoid meddling with constructors. Passing the right stuff
to super etc.

------
brianvaughn
To go along with this blog post, a 16.3 release candidate has just been
published to npm.

    
    
        yarn add react@next react-dom@next
    

Please let us know if you encounter any problems!

------
johnzim
I was a little worried until I read the replacement functions which are
basically word-for-word descriptions of what I use the functions for:

getSnapshotBeforeUpdate, getDerivedStateFromProps

------
dvt
React is such a mess.

> These lifecycle methods have often been misunderstood and subtly misused;
> furthermore, we anticipate that their potential misuse may be more
> problematic with async rendering.

I hate it when library authors blame users (consuming developers in this case)
for their blunders. Almost all lifecycle methods in React are confusing and
contrived. The state mechanisms are becoming so convoluted (and overly
generalized), no wonder we're ending up with gobbledygook like
"getSnapshotBeforeUpdate(...)."

It's also pretty funny (or sad) to see no mention of SSR. Just a few months
ago I spent literally weeks trying to figure out how to do server-side
rendering with React. I ended up populating data via componentWillMount on the
back-end. Terrible solution, but hey, it's the only one React has. Now, they
suggest moving data-population in componentDidMount.. but guess what?

This _will not work_ on the server-side because technically components _never
mount_ when doing SSR.

~~~
always_good
I don't get it. They admitted the methods were confusing and then made them
more explicit. And all you have to add is that they're blaming people for
being confused?

------
Waterluvian
I hope this feeling passes, but I get nervous when code example syntax starts
looking _really_ foreign to me. Whether accurate or not, my brain is kind of
in a place of, "okay so ES6 cleaned up a lot, we're all kind of settling on
Webpack, npm, certain various toolsets and best practices. I don't feel
constantly overwhelmed anymore, can we not rush into another flurry of
change?"

On the other hand, it looks like we're streamlining some verbosity. I just
hope we can be okay with the right balance and we don't end up with a _really_
terse looking language.

~~~
losteric
FYI, the examples are partially written in Typescript not ES6... so they
should look foreign.

~~~
kevmo314
What parts are in Typescript? This looked like all ES6 to me.

~~~
losteric
Never mind, they updated the post. As of my post the first few examples had
some type annotations in the form `methodName(varName: type, ...)`, which I
assumed was TS. All the examples are plain ES6 now.

------
yiransheng
Interesting mention of create-subscription[1], first time I have heard of such
a library/api. Seems it's part of official react repo. Looks like a great
piece of utility for interfacing rxjs/xstream etc. Observables. I guess this
may replace recompose[2]'s Observable utilities as it's officially endorsed by
react team.

Current react ecosystem broadly speakings splits on state management solutions
in two styles: 1\. Single Observable-like source of truth (redux store) 2\.
Multi-Observables (relay, appolo, mobx)

It will be interesting to see if `create-subscription` catches on, and whether
library authors will start exporting subscriptions as public apis.

[1] [https://www.npmjs.com/package/create-
subscription](https://www.npmjs.com/package/create-subscription)

[2]
[https://github.com/acdlite/recompose/blob/master/docs/API.md...](https://github.com/acdlite/recompose/blob/master/docs/API.md#observable-
utilities)

~~~
acemarke
That's because it's a new addon library from the React team, intended to help
handle several tricky bits of timing and behavior in how updates get passed to
React.

------
hoodoof
Hang on, I use componentWillReceiveProps in just about every large non-
function component I build.... I just counted 50 times in one of my
applications.

and its going as soon as V17? Too early.

~~~
xnxn
The post says the UNSAFE_ versions will continue to work in V17

~~~
hoodoof
I like my code to be safe.

~~~
a_t48
The functionality is the same, it’s just being marked as dangerous to use.
Your code is just as (un)safe as before.

------
davnicwil
For async data loading for components, you can use this library today:
[https://github.com/davnicwil/react-
frontload](https://github.com/davnicwil/react-frontload) (npm react-
frontload). I'm the author.

It lets you define a promise-returning data loader function for any component
at any depth in the tree, which will run synchronously on the server and
asynchronously on the client.

All you have to do is wrap your app in a provider, and add a single extra line
of code to the server (since the sync server rendering relies on running the
render once, waiting, then running again once all data is loaded for every
component in the tree). You can find much more detail and examples in the
blogpost linked from the github repo.

I'm really excited about async data loading coming to 'native' React, I
essentially wrote react-frontload as a polyfill for this feature and hopefully
my library won't be necessary any more once it's released. But for now, and in
the future for projects that won't be able to update to the latest React,
there it is. I've been pretty happy using it in production, and I hope it's
useful for others too!

~~~
sktrdie
This is not how Suspense works. It doesn't just add loading states to your
component, so a new primitive is needed and a polyfill won't do. With Suspense
if a component renders async data, you can simply wait (notice, different from
showing a loader) for it to finish.

In essence, React has a new primitive where calling setState will try to
render the tree, but only flush changes to the DOM once all the components in
the tree have finished loading. If you call setState again during this process
(the app is still usable while waiting), and changes are to be made on the
same portion of the tree that's currently loading async data, then React will
simply dismiss the old tree from ever rendering - fixing race conditions in a
natural/clever way.

~~~
davnicwil
Thanks. I've yet to look into the details, but my intuition was that Suspense
could be a 'native' solution for synchronous rendering _on the server_ \- this
is basically the missing feature in React itself that I was talking about
needing to polyfill - essentially via a wasteful workaround that requires two
server renders to be run instead of one.

The client side thing of implementing async loading with a loading prop and
componentDidMount obviously has to be done 'manually', this is straightforward
and not something I'd expect React or even a library to solve - what react-
frontload does though is gets the same component to also synchronously load
that same data (using the same function) on server render. This is much more
fiddly and is way too much boilerplate to write manually for each component,
not to mention that you need some global context to tie all the promises
together. That's the problem that react-frontload solves - the client side
loader thing is up to you to implement, even with react-frontload.

What I'm hoping is that it _may_ be possible to go back to writing this stuff
manually on certain components, because it'll be simple enough with Suspense -
or at least just make the implementation of react-frontload much simpler and
carry on using it as syntax sugar (it's quite nice to just define an async
data loading function via a HOC, for instance - you obviously wouldn't get
that having to hand code lifecycle methods for each component).

~~~
danabramov
Suspense is both for client and server.

 _> The client side thing of implementing async loading with a loading prop
and componentDidMount obviously has to be done 'manually', this is
straightforward and not something I'd expect React or even a library to solve_

The problem Suspense is solving on the client is not straightforward. But
you'll need to see my demo (second part of this talk[1]). It's very hard to
talk about in abstract without seeing it.

The big difference Suspense brings is the ability to _wait with the whole
state transition_ until all leaves are ready. Think transitioning between
pages (that need data) is as easy as updating state in the parent, and React
takes care of “waiting” for the page to be ready before displaying it (or
falling back to a placeholder).

 _> This is much more fiddly and is way too much boilerplate to write manually
for each component, not to mention that you need some global context to tie
all the promises together_

Suspense takes care of that, you don’t need to manually collect Promises.

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

~~~
davnicwil
Cool - I will definitely go actually figure out what Suspense does in detail.
Thanks for the link!

Now you've got me thinking, and you're right. Even in a client-only case, the
simple spinner-until-data-loaded pattern works for a solo component just fine,
but doesn't at all account for waiting for children, etc, without implicit
dependencies between parent and child. If you've got stuff like that going on,
then yes this is a pretty complex problem.

It does definitely seem like Suspense is going to remove most of the
complexity involved in the 'synchronous' server render problem, especially
with regards to manual promise collection. This is awesome work :-)

------
hoodoof
The Context API is of most interest for me.

I love Redux but I find myself using it less than I want to because so much
stuff has to be put in place any time I want to store some stuff.

------
martin_drapeau
Can someone explain the types of bugs and pitfalls one ends up having when
using componentWillMount, componentWillReceiveProps, and componentWillUpdate?

~~~
brianvaughn
The RFC for getDerivedStateFromProps
([https://github.com/reactjs/rfcs/blob/master/text/0006-static...](https://github.com/reactjs/rfcs/blob/master/text/0006-static-
lifecycle-methods.md#common-problems)) mentions a few!

• Initializing Flux stores in componentWillMount. It's often unclear whether
this is an actual problem or just a potential one (eg if the store or its
dependencies change in the future). Because of this uncertainty, it should be
avoided.

• Adding event listeners/subscriptions in componentWillMount and removing them
in componentWillUnmount. This causes leaks if the initial render is
interrupted (or errors) before completion.

• Non-idempotent external function calls during componentWillMount,
componentWillUpdate, componentWillReceiveProps, or render (eg registering
callbacks that may be invoked multiple times, initializing or configuring
shared controllers in such a way as to trigger invariants, etc.)

Edit: For formatting

------
aravindet
From the post it looks like getDerivedStateFromProps does not receive the old
props as an argument. I can think of cases where that would be helpful, has
this been considered?

~~~
marcins
I don't think you need it - since you're deriving state from props you can
just derive from the new props and compare to the old state. At least I
believe that's the reasoning.

~~~
aravindet
In my use case, the component receives the URL of a resource as a prop, and it
re-fetches the resource from a backend when the URL changes. I'd like to avoid
the expensive fetch when it's some other prop that changed.

Copying the URL to the state will work, although it's a bit more verbose.

~~~
marcins
That's probably something that belongs in `componentDidUpdate`, you'll have
access to `prevProps` there to compare whether you need to trigger a new
fetch. I don't believe that `getDerivedStateFromProps` should have any side-
effects.

------
bennyg
The suspense demo is fantastic, and I really can't wait to get 16.3 into
production code. The async rendering clean up and the new Context API make my
heart sing.

~~~
brianvaughn
The suspense demo is fantastic! But that won't be a part of 16.3 - maybe 16.4!

16.3 does have some goodies though- new context API, forwardRef, etc.

------
ixtli
I hate using componentWillReceiveProps but always end up doing so because it
seems to be the easiest with redux. The static function replacement seems very
natural.

~~~
pknopf
I'm not shilling, but this is something I definitely don't miss using Mobx.

edit: Ooops, I thought the commenter was referring to shouldcomponentupdate.
Sorry for the confusion, please downvote this out of the discussion!

~~~
spicyj
What is the alternative? For when you have a stateful component that "reacts"
to new parameters.

~~~
pknopf
Mobx uses observables to monitor what properties you read and collections you
enumerate during your render method.

It then uses that information to implement shouldComponentUpdate for you. Each
render call refreshes the data use by shouldComponentUpdate.

It gives you 100% percise updating of react components based on state, for
free.

~~~
spicyj
Were we not talking about componentWillReceiveProps, not
shouldComponentUpdate?

~~~
pknopf
Shoot, my bad. Sorry for the confusion. That is a common common complaint with
redux, so I read into it.

~~~
spicyj
No worries, I was just confused what you meant. :)

------
polskibus
I wonder if they considered a new base class instead, for example
reactAsyncComponent? That way developer as to declare his component as async-
safe explicitly, without all that hard to follow rename thing. Engine could
recognize async classes and perform rendering differently for them.

~~~
danabramov
Yes, we considered it. Two arguments against this:

1\. A single “async component” is useless because the power of async rendering
is in letting React coordinate the work _of the whole tree_. As long as just
one leaf isn’t async-compatible, the whole tree isn’t.

2\. In practice most components already _are_ async-compatible. So we don’t
want to hold off progress by forcing people to explicitly specify it. Instead
the plan is to outlaw patterns that we know _won’t_ work.

Hope this makes sense.

~~~
polskibus
It does, thanks. Hopefully there will be a set of dev warnings, tests or sth
that a developer can read or run that will help him verify whether the
component tree is "async-ready".

BTW, I've watched your jsconf, great presentation, can't wait to use all those
goodies (also love HN for a chance of response straight from react core team
:)

~~~
danabramov
>Hopefully there will be a set of dev warnings, tests or sth that a developer
can read or run that will help him verify whether the component tree is
"async-ready".

We'll offer a <StrictMode> component in React 16.3 that warns about some
unsafe patterns (like legacy lifecycles and a few other issues). Later on
we'll provide more testing tools for libraries.

------
cloverich
This is a bold, dangerous move. I can get on board with these lifecycle
methods being abused, and instituting changes to the library to correct them.
However, I suspect there's an unimaginable amount of code that will need re-
written to accommodate these changes. Is that a feasible expectation? Would it
have been feasible to re-brand the library (or components) to support async
rendering (with async components having that different API)? I don't know; I"m
all in on React so I really hope this doesn't result in community split.

~~~
acemarke
As the post says, the migration will be handled gradually. All of the semi-
deprecated `componentWill` lifecycles will continue to work as-is as long as
you're on React 16.x. They'll start warning about using them in a later 16.x
release. If you rename them to `UNSAFE_componentWill`, they'll continue to
work the same way, and there will be a codemod released to do that
transformation automatically. There will also be a `<StrictMode>` component
built in to React that you can explicitly put around parts of your component
tree to help locate these usages.

~~~
brianvaughn
Just chiming in to note that the codemod has already been released:
[https://github.com/reactjs/react-codemod#rename-unsafe-
lifec...](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles)

We used it internally (at Facebook) several weeks ago to update ~14,000
components that used the unsafe lifecycles.

------
drudru11
Where can I read about the internals that make this work? For example, how
does the scheduler work? Does it still compute a tree for an old setstate or
does it unschedule existing computations when a new high priority setstate
ones in?

Update:

I took a look at their work on fibers. It looks like they are manually
deciding on what is or is not enough computation to perform in a fiber. This
is fine, but it will require some careful attention by the react team.

It would be neat if they could use web workers for some of this.

------
thomasfromcdnjs
Great work!

Could be a good idea to try draw some diagrams too =)

~~~
danabramov
We made a few!

[https://mobile.twitter.com/acdlite/status/977291318324948992](https://mobile.twitter.com/acdlite/status/977291318324948992)
[https://mobile.twitter.com/acdlite/status/978412930973687808](https://mobile.twitter.com/acdlite/status/978412930973687808)

Will put them in some future blog post.

~~~
thomasfromcdnjs
Awesome! I did see these.

An official life cycle flow would be awesome too.

In the past, when teaching other developers, I just throw a dart at one of the
many google image search results that try show the flow.

------
rdsubhas
This goes directly against their own versioning policy of abusing cliffs and
bringing everyone along: [https://reactjs.org/blog/2016/02/19/new-versioning-
scheme.ht...](https://reactjs.org/blog/2016/02/19/new-versioning-scheme.html)

Quoting from that page:

> Therefore it is important that we don’t just upgrade our own codebases but
> that we bring our whole community with us. We take the upgrade path very
> seriously - for everyone.

> If we’re not careful, we can hit a cliff where nobody upgrades. This has
> happened to many software project ecosystems in the past.

> Therefore, we’re committed to making it easy for most components and
> libraries built on top of React to be compatible with two major versions at
> the same time.

I'm not sure if I'm reading them and the diagrams in that page correctly, but
looks like the deprecation should happen at 17 and removal at 18 according to
it?

~~~
audiolion
> Minor revision releases will include deprecation warnings and tips for how
> to upgrade an API or pattern that will be removed or changed in the future.

16.3 is including dep warnings and tips to upgrade, check.

> We will continue to release codemods for common patterns to make automatic
> upgrades of your codebase easier.

Probably will be there closer to 17 release.

> Once we’ve reached the end of life for a particular major version, we’ll
> release a new major version where all deprecated APIs have been remove

Once 16.x end of life is reached, the next major version, 17, will remove the
deprecated APIs, check.

They are literally following exactly what they said.

~~~
danabramov
Note 16.3 doesn’t even include warnings. We are only adding support for the
new aliases at this point, but won't fire warnings until the biggest ecosystem
libraries have updated with recommendations in the blog post.

Yes, there will also be a codemod for the "UNSAFE_" rename.

~~~
brianvaughn
One of the main focuses of 16.3 is to enable open source libraries to update
their code in advance of deprecation warnings. (We're trying to go one step
beyond SEMVER- so that application developers don't have to be bothered by
warnings in third party code that they can't change.)

And the codemod has already been released: [https://github.com/reactjs/react-
codemod#rename-unsafe-lifec...](https://github.com/reactjs/react-
codemod#rename-unsafe-lifecycles)

We've used it internally (at Facebook) to update ~14,000 components already,
so it's well tested.

------
mariusmg
getDerivedStateFromProps , getSnapshotBeforeUpdate

Java is leaking on the client side ...

~~~
borplk
Unfair and ignorant comment.

They are descriptive function names, that's all.

"derived state from props" 4 words.

"snapshot before update" 3 words.

If you get an allergic reaction from that it's just you.

------
nukeop
Why call it "UNSAFE_" if there isn't really anything unsafe about it? I get
it, they don't want people using those functions, but why should they decide
what work best for other developers and use shady tactics like dishonestly
calling something they don't want to be used "unsafe" just so that it causes
uneasiness and raises red flags with devs that aren't intimately familiar with
React? Facebook is known for its underhanded tactics and React is no
exception, they tried to kill patent disputes with its licensing in the past.
Now they're trying to control how their library is used in a very deceitful
way.

~~~
danabramov
_> Why call it "UNSAFE_" if there isn't really anything unsafe about it_

After seeing thousands of React components and responding to thousands of
issue reports, we know which patterns often get people in trouble. Some of
these patterns indicated bad design on our part, and we want to fix those
issues.

We are adding safer alternatives for these use cases that don’t have those
pitfalls. Importantly, we want to clearly communicate that these existing
methods cause problems _and these problems will become more noticeable in
future versions of React that will support asynchronous rendering_.

I gave a talk about what “asynchronous rendering” means for React, and about
exciting new long-requested features it enables.[1] I encourage you to watch
it if you’re curious about our motivations. These methods are incompatible
with it, hence they’re “unsafe”. Since the risk of them being unsafe grows
with time, we decided it’s worth adding a prefix to call them out in the
product code.

We’re trying to do best by our community and I’m sorry if we’re falling short
of that. We set up an RFC repository[2] a few months ago so you’re welcome to
give us feedback on the future changes.

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

[2]: [https://github.com/reactjs/rfcs](https://github.com/reactjs/rfcs)

~~~
nukeop
Why not just deprecate this API in addition to providing a better way to
perform operations commonly invoked this way?

~~~
brianvaughn
We are trying to strike a balance between supporting huge legacy apps that
cannot be rewritten- (something Facebook has a lot of)- and encouraging
safe/bug-free coding practices for future apps. In this case, we felt the
right balance was to preserve legacy functionality while using a name that
would hopefully discourage new usage (so as to avoid the potential pitfalls
inherent in the legacy API).

And we provided a codemod to help with the "huge legacy apps":
[https://github.com/reactjs/react-codemod#rename-unsafe-
lifec...](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles)

We've run it internally already to update ~14,000 components.

