14 ms·
Update on Async Rendering
- thomasfromcdnjs 9y agoGreat work! Could be a good idea to try draw some diagrams too =)
- danabramov 9y agoWe 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 9y agoAwesome! 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.
- bennyg 9y agoThe 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 9y agoThe 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.
- bhj 9y ago> 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 9y agoWhen 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__ 9y agoI 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 9y agoIf 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-rendering.html#other-scenarios https://reactjs.org/blog/2018/03/27/update-on-async-renderin...
- k__ 9y agoI know, but I often avoid meddling with constructors. Passing the right stuff to super etc.
- TheCoelacanth 9y ago
- johnzim 9y agoI 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
- Waterluvian 9y agoI 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.
- timwis 9y agoIt looks strange to me, too. It looks like they using typescript in their examples, probably to be more descriptive.
- danabramov 9y agoIt is Flow. We were trying to be descriptive for folks who already use it (like we do at FB) so they know the intended type signatures, but the same changes apply if you skip the types. Sorry it came across as confusing.
- danabramov 9y agoI edited the post to hide the annotations behind a gist: https://github.com/reactjs/reactjs.org/pull/719 https://github.com/reactjs/reactjs.org/pull/719 Hope this is clearer now!
- Waterluvian 9y agoThanks, Dan. I can appreciate the value that Flow adds. But in my opinion, when it's default in the code examples of a top shelf library, it creates an implicit dependency to learning from the blog post, no matter how small or obvious it may be.
- losteric 9y agoFYI, the examples are partially written in Typescript not ES6... so they should look foreign.
- ixtli 9y agoI 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 9y agoI'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!
- nawgszy 9y agoIs it possible to shill for an open source library which, as far as I can tell, has no monetization path?
- pknopf 9y agoIf you are going to get technical, ask James Newton-King what Json.NET did to his career trajectory. It definitely has an intangible value.
- spicyj 9y agoWhat is the alternative? For when you have a stateful component that "reacts" to new parameters.
- pknopf 9y agoMobx 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 9y ago
- hoodoof 9y agoThe 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.
- dvt 9y agoReact 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 9y agoI 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?
- deleted 9y ago[deleted]
- danabramov 9y ago>I hate it when library authors blame users (consuming developers in this case) for their blunders. I’m sorry the post came across this way. We didn’t intend to blame the users. The component API was virtually unchanged for five years, and when it was originally designed, we didn’t anticipate how it would be used, so the hooks were pretty low level and matched how React worked internally. These days we have a better idea of where we want to take React (I hope that my talk[1] may inspire you even though you already formed a negative opinion). The work we're doing now is just to fix the mistakes we made in the past with a gradual migration path. >no wonder we're ending up with gobbledygook like "getSnapshotBeforeUpdate(...)." I totally see what you mean but this particular lifecycle is for a very rare use case. If you have better suggestions for naming it please let us know—we have an open RFC process and you are welcome to participate there.[2] We didn’t separate it on a whim—it is essential to have a pure lifecycle like this to implement some use cases (like autoscrolling to new data) with asynchronous rendering[1]. >I ended up populating data via componentWillMount on the back-end. Terrible solution, but hey, it's the only one React has You're right—but this solution doesn't solve async data fetching. It only works when the data is synchronously available, and per the post, in that case you can already use the constructor.[3] >This will not work on the server-side because technically components never mount when doing SSR. I think you might have missed this part of the post: >In the longer term, the canonical way to fetch data in React components will likely be based on the “suspense” API introduced at JSConf Iceland. Both simple data fetching solutions and libraries like Apollo and Relay will be able to use it under the hood. It is significantly less verbose than either of the above solutions, but will not be finalized in time for the 16.3 release. The mentioned “suspense” API is both much less verbose and actually was designed with server rendering in mind. It would let us fetch data on the server and on the client and suspend rendering until the data is ready (and show a placeholder if it takes too long). The lifecycle changes in these blog posts are exactly the kind of work we need to do to make APIs like Suspense possible. Again, I encourage you to watch my talk[1], the second half of which demonstrates this API. I hope this clarifies our position a bit, and I’m sorry if it seemed like we don’t care about our users. It took us about a month to write this blog post, and we know it still doesn’t address all use cases. We’ll take your feedback in mind next time we amend it. Thanks! [1]: https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-... [2]: https://github.com/reactjs/rfcs/pull/33 https://github.com/reactjs/rfcs/pull/33 [3]: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state https://reactjs.org/blog/2018/03/27/update-on-async-renderin...
- brianvaughn 9y agoTo 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!
- aravindet 9y agoFrom 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?
- danabramov 9y agoYes. Our recommendation is to put such values on the state (like state.prevRow in the blog post example). This frees up React to not hold into the whole previous props object in some cases in future versions. It’s a bit more verbose but it also solves the problem of prevProps being null on first render (and thus forcing you to write an extra check every time you use this method).
- marcins 9y agoI 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 9y agoIn 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 9y agoThat'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.
- brianvaughn 9y agoThis was implied but not explicitly covered in the blog post. I updated it this morning to be more explicit [1]! > You may notice in the example above that props.currentRow is mirrored in state (as state.lastRow). This enables getDerivedStateFromProps to access the previous props value in the same way as is done in componentWillReceiveProps. > You may wonder why we don’t just pass previous props as a parameter to getDerivedStateFromProps. We considered this option when designing the API, but ultimately decided against it for two reasons: > * A prevProps parameter would be null the first time getDerivedStateFromProps was called (after instantiation), requiring an if-not-null check to be added any time prevProps was accessed. > * Not passing the previous props to this function is a step toward freeing up memory in future versions of React. (If React does not need to pass previous props to lifecycles, then it does not need to keep the previous props object in memory.) 1: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props https://reactjs.org/blog/2018/03/27/update-on-async-renderin...
- yiransheng 9y agoInteresting 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#observable-utilities https://github.com/acdlite/recompose/blob/master/docs/API.md...
- acemarke 9y agoThat'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 9y agoHang 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 9y agoThe post says the UNSAFE_ versions will continue to work in V17
- a13n 9y agoWhy do you need to use that method so often?
- danabramov 9y agoCurious, what do you use it for?
- hoodoof 9y agoI use it to handle changes in props. For example load something from network, which goes into redux, redux triggers a props update, so then I do something because for example now redux state has changed to say "loaded === true" Is this not the correct function to handle changes in props?
- spicyj 9y agoWhen you see that the props have changed, what do you do? (You said you do "something".) If you are updating the state of that component, that's exactly what the new getDerivedStateFromProps is designed for. If you are doing something else (esp. fetching other data or some other side effect), componentDidUpdate is likely the best place (it receives prevProps as an argument, so you can compare old and new).
- polskibus 9y agoI 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 9y agoYes, 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 9y agoIt 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 9y ago>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.
- davnicwil 9y agoFor 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 9y agoThis 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 9y agoThanks. 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).
- rdsubhas 9y agoThis goes directly against their own versioning policy of abusing cliffs and bringing everyone along: https://reactjs.org/blog/2016/02/19/new-versioning-scheme.html https://reactjs.org/blog/2016/02/19/new-versioning-scheme.ht... 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 9y ago> 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 9y agoNote 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 9y agoOne 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-lifecycles https://github.com/reactjs/react-codemod#rename-unsafe-lifec... We've used it internally (at Facebook) to update ~14,000 components already, so it's well tested.
- mariusmg 9y agogetDerivedStateFromProps , getSnapshotBeforeUpdate Java is leaking on the client side ...
- borplk 9y agoUnfair 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.
- deleted 9y ago[deleted]
- martin_drapeau 9y agoCan someone explain the types of bugs and pitfalls one ends up having when using componentWillMount, componentWillReceiveProps, and componentWillUpdate?
- danabramov 9y agoRace conditions and memory leaks are pretty common. Side effects that wouldn't be safe to repeat (which is what happens with async rendering). There is also sometimes a reliance on these methods happening synchronously (which again wouldn't work with async rendering).
- Blackstone4 9y agoTaken from my comment above: "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...." I didn't really understand how React worked underneath and I thought these functions would be helpful. But they weren't...
- brianvaughn 9y agoThe RFC for getDerivedStateFromProps (https://github.com/reactjs/rfcs/blob/master/text/0006-static-lifecycle-methods.md#common-problems https://github.com/reactjs/rfcs/blob/master/text/0006-static...) 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
- nukeop 9y agoWhy 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 9y ago>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-16.html https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-... [2]: https://github.com/reactjs/rfcs https://github.com/reactjs/rfcs
- nukeop 9y agoWhy not just deprecate this API in addition to providing a better way to perform operations commonly invoked this way?
- 9y ago
- cloverich 9y agoThis 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 9y agoAs 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 9y agoJust chiming in to note that the codemod has already been released: https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles https://github.com/reactjs/react-codemod#rename-unsafe-lifec... We used it internally (at Facebook) several weeks ago to update ~14,000 components that used the unsafe lifecycles.
- danabramov 9y agoMy answer here is relevant to this question: https://news.ycombinator.com/item?id=16696798 https://news.ycombinator.com/item?id=16696798
- drudru11 9y agoWhere 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.