> 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.
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.
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.
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.
> 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.
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?
Subverting and abusing UI lifecycle methods has a history as long as UI components have existed.
As a former Adobe Flex dev I had to maintain mountains of scream inducing code I had to maintain that was littered with callLaters - the clearest sign the other dev didn't understand the component lifecycle.
>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!
My apologies if I came off harsh, I have a love-hate relationship with React.
> I totally see what you mean but this particular lifecycle is for a very rare use case.
It's not that rare. Consider a route change where some state needs to be preserved or, like the article mentions, a scroll position change (or reset!).
> 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]
I just want to point out how fundamentally flawed this is. The constructor is meant to initialize internal and initial state of objects. Making a data/network request in the constructor is beyond bizarre. In fact, the general consensus was that doing that sort of thing in the constructor is kind of an antipattern[1].
> 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).
I'll have to check out suspense, but I feel that it's yet another API that reinvents the wheel. We'll see.
> I just want to point out how fundamentally flawed this is. The constructor is meant to initialize internal and initial state of objects. Making a data/network request in the constructor is beyond bizarre. In fact, the general consensus was that doing that sort of thing in the constructor is kind of an antipattern.
Note that he said synchronous data fetching, ie a local cache. If you are querying a local cache, this enables you to grab data before the first render (saving a re-render) which is more obviously beneficial on low-power, slow-to-render devices.
It CAN also be used to initiate a network request, but this is discouraged because it can fire multiple times: meaning you should only do this if the endpoint is idempotent and you can live with excess requests. It may also complicate testing.
Bit OT, but I generally think "that's an anti-pattern" criticism isn't a great contribution unless you're specifying what the problem is.
I mean detailing specifically what problems arise. To my mind, calling something a 'terrible practice ... against common sense',
particularly when another party (with expertise no less) disagrees, is just a lazy put-down.
I can be clearer if you need me to, but I think this is very common knowledge: the advice of "stick it in the constructor" abuses constructors and makes them do something they weren't meant to do. Incidentally, abusing constructors also sometimes breaks testing. Constructors (in virtually all languages) are notoriously difficult to test as is[1].
>It's not that rare. Consider a route change where some state needs to be preserved or, like the article mentions, a scroll position change (or reset!).
In my anecdotal experience this code is still pretty rare (compared to overall number of components). You don't need this hook to reset scroll position (`componentDidUpdate` alone is sufficient) or maintain it (browser does this automatically if the inserted DOM height is enough to cover it).
The use case for `getSnapshotBeforeUpdate` refers to cases where you have a list that needs to track its current position during offscreen insertions (for example, new items loaded above in the feed) or a list that “catches up” with new content (for example, a message thread that auto-scrolls to the last message unless you’re in the middle of a conversation).
>The constructor is meant to initialize internal and initial state of objects. Making a data/network request in the constructor is beyond bizarre.
I am not suggesting to do network requests in it. Please see the link I pointed to: it shows initializing initial state. Not data fetching.
To be clear: today in React there is no way to asynchronously fetch data on the server. It’s just not supported (and we’re aware it’s an unfortunate limitation). So if the data is already available synchronously (which in your case it seems to be because you said you were able to use `componentWillMount` for this which is also synchronous on the server), then you can synchronously read it in the constructor. If it’s not available synchronously, then there’s nothing `componentWillMount` gives you anyway.
In either case, this limitation is exactly what motivates our work on React Suspense (which will support waiting for data both on the server and on the client). But to support this API, we need to make component compatible with async rendering first. Which is what this blog post is all about.
>I'll have to check out suspense, but I feel that it's yet another API that reinvents the wheel. We'll see.
You’re welcome to start watching the RFC repository and comment when we post more technical details about it. We think it adds a capability that’s always been missing in React (pausing rendering while keeping the screen consistent) and I hope you’ll find it useful.
The downside of this is that the cost of rendering is multiplied. We know it’s an existing workaround but it’s not a good long term solution. We want to enable something better.
>Removing componentWillMount will force us to rewrite everything to the suspense API.
This is not accurate. The blog post states that `UNSAFE_componentWillMount` is here to stay so you can keep using that until we have a first-class data fetching solution that works both on the client and the server. You can also use the constructor for this (it’s technically equivalent to `componentWillMount`).
While it contradicts what I said earlier (avoid side effects in constructor) you’re already using a hack (rendering twice) and I’d argue this is no worse as a temporary solution. Don’t forget that `componentWillMount` is equivalent to the constructor for all intents and purposes, and only exists because it predates ES6 classes (and the ability to define a constructor). So you were already doing side effects in what is effectively a constructor.
Still, the upcoming Suspense API mentioned in the blog post is the intended long term solution to this. It will work both on the client and the server, and it will allow you to remove the double rendering hack. But to prepare for Suspense, we need to make components compatible with async rendering (which is what the blog post is all about).
We added a section to the blog post which I hope clarified it:
>When supporting server rendering, it’s currently necessary to provide the data synchronously – componentWillMount was often used for this purpose but the constructor can be used as a replacement. The upcoming suspense APIs will make async data fetching cleanly possible for both client and server rendering.
So you can keep using `UNSAFE_componentWillMount` or constructor for now, and migrate to Suspense when it’s ready (and render your app in a single pass).
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.
For the first two examples, there's some unfamiliar syntax because they added Flow[1] typings to the examples (not TypeScript as other comments are suggesting).
What about the syntax do you find confusing? The rest is all just ES6 + class properties.
Yes, since that’s the most common issue with what people do in componentWillReceiveProps. It is invoked during the interruptible phase in async mode so mutations and side effects are unsafe there. Same as in the render method.
It 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.
Thanks, 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.
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.
Oh god, I really don't hope we're settling on webpack. Unless you just want to pull the ladder out from web devs with mediocre machines (we don't all have californian salaries).
You actually think 30 seconds is OK for 'compiling' a dynamic language? We might as well start using C++ in the browser if that's the kind of feedback loop we have to deal with.
Bundler != compiler. With caching my babel webpack setup has 30s cold startup and <1s compile and reload for a huge huge code base
Edit: I should say bundler != tranpiler. A bundler may or may not be implemented as a compiler. In the end it's just fancy concatenation and code generation, whereas a transpiler (going from one language to another) requires parsing to an AST
In production builds, yes. Webpack is massively plugable - you could probably use it to build C++ if you wanted (tho.. why). So for web production builds minification plugins are used (Uglify is bundled, but Closure Compiler, etc can be used too).
But there's nothing about webpack that requires an AST, it can use things that do tho.
The other comment cited 30 seconds as an upper limit where it becomes clear that something bad is likely going on. The dynamic language tidbit is a red herring, since the compilation is from one language into a dynamic language, which does have some valid downsides but is widely accepted (including by yourself, if you’ve accepted Browserify).
Moreover, the full build times are, at least in my experience with webpack starter packs for side projects and much larger webpack builds at work, only a cost you pay when deploying or setting up a dev environment for the first time. My local dev environments recompile only the parts of the codebase that they need to, and that usually happens quickly enough that it’s ready by the time I go to my browser and refresh.
On a big project I use, the full compilation takes 20s but the watch part only takes 2s, so when you work, you only wait one time 20s, after that it's only 2s.
A) no I don’t because it’s not “compiling” anything B) learn the meaning of things before you try to sound knowledgeable about them C) switching off Browserify sped up bundling by 200% on my development build and about 500% on my production build. You’re doing something wrong.
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.
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.
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.
You will be able to continue to use this method in version 17. You'll just need to run a codemod [1] to rename it to "UNSAFE_ componentWillReceiveProps". It will otherwise work the same as it always has.
We are trying to strike a balance between supporting huge legacy apps- (something Facebook has to do for itself too)- and encouraging safe/bug-free coding practices for future apps.
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?
When 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).
I'd also add that in general we suggest there to be one source of truth for any data. For any particular data, you could put it in Redux -or- in local state, but there is rarely a need to keep it in both.
Manually copying things from Redux into local state from `componentWillReceiveProps` (or even with new `getDerivedStateFromProps`) seems unnecessary to me. There are exceptions like rare cases where you want to have a “draft” of some state that can later be “reverted”. But in general you wouldn't want to “sync” state from one source to another.
>> When you see that the props have changed, what do you do?
"What do I do in componentWillReceiveProps?" It's a good question. Looking through the code I see alot of cases in which I am mapping new props to state, sometimes transforming received network data that is stored in redux, sometimes making a barrier to redirect to a different page if for example some condition has changed.
Perhaps these things are relics from before I really came to understand Redux - maybe in most cases I can just directly use props rather than having an intermediate setting of state.
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!
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.
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).
>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.
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 :-)
Can someone explain the types of bugs and pitfalls one ends up having when using componentWillMount, componentWillReceiveProps, and componentWillUpdate?
• 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.)
Taken 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...
Race 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).
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?
Yes. 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).
This 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.)
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.
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.
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.
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.
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.
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.
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.
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 :)
>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.
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.
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.
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.
> 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?
> 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.
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.
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.)
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.
>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.
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).
That’s the plan (and it’s what the blog post says).
However both Facebook and large products at other companies have too much code that depends on those lifecycles. Potentially thousands of components. So it’s infeasible to completely deprecate them. At least not within a time frame of a year.
This is why we’re still leaving the “unsafe” aliases in React 17 so that people can opt out of async rendering and keep using those while they’re not ready to migrate.
Since we need some version of the hooks to stay, we need to clearly differentiate them so that new code doesn’t use them. Hence the prefix.
It's a common pattern in functional programming (e.g. in Haskell and Scala) to add an "unsafe" prefix or suffix to functions that perform dangerous side effects.
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.