Source: React Blog

React Blog React v17.0 Release Candidate: No New Features

Today, we are publishing the first Release Candidate for React 17. It has been two and a half years since the previous major release of React, which is a long time even by our standards! In this blog post, we will describe the role of this major release, what changes you can expect in it, and how you can try this release.No New FeaturesThe React 17 release is unusual because it doesn't add any new developer-facing features. Instead, this release is primarily focused on making it easier to upgrade React itself.We're actively working on the new React features, but they're not a part of this release. The React 17 release is a key part of our strategy to roll them out without leaving anyone behind.In particular, React 17 is a "stepping stone" release that makes it safer to embed a tree managed by one version of React inside a tree managed by a different version of React.Gradual UpgradesFor the past seven years, React upgrades have been "all-or-nothing". Either you stay on an old version, or you upgrade your whole app to a new version. There was no in-between.This has worked out so far, but we are running into the limits of the "all-or-nothing" upgrade strategy. Some API changes, for example, deprecating the legacy context API, are impossible to do in an automated way. Even though most apps written today don't ever use them, we still support them in React. We have to choose between supporting them in React indefinitely or leaving some apps behind on an old version of React. Both of these options aren't great.So we wanted to provide another option.React 17 enables gradual React upgrades. When you upgrade from React 15 to 16 (or, soon, from React 16 to 17), you would usually upgrade your whole app at once. This works well for many apps. But it can get increasingly challenging if the codebase was written more than a few years ago and isn't actively maintained. And while it's possible to use two versions of React on the page, until React 17 this has been fragile and caused problems with events.We're fixing many of those problems with React 17. This means that when React 18 and the next future versions come out, you will now have more options. The first option will be to upgrade your whole app at once, like you might have done before. But you will also have an option to upgrade your app piece by piece. For example, you might decide to migrate most of your app to React 18, but keep some lazy-loaded dialog or a subroute on React 17.This doesn't mean you have to do gradual upgrades. For most apps, upgrading all at once is still the best solution. Loading two versions of React - even if one of them is loaded lazily on demand - is still not ideal. However, for larger apps that aren't actively maintained, this option may make sense to consider, and React 17 enables those apps to not get left behind.To enable gradual updates, we've needed to make some changes to the React event system. React 17 is a major release because these changes are potentially breaking. In practice, we've only had to change fewer than twenty components out of 100,000+ so we expect that most apps can upgrade to React 17 without too much trouble. Tell us if you run into problems.Demo of Gradual UpgradesWe've prepared an example repository demonstrating how to lazy-load an older version of React if necessary. This demo uses Create React App, but it should be possible to follow a similar approach with any other tool. We welcome demos using other tooling as pull requests.NoteWe've postponed other changes until after React 17. The goal of this release is to enable gradual upgrades. If upgrading to React 17 were too difficult, it would defeat its purpose.Changes to Event DelegationTechnically, it has always been possible to nest apps developed with different versions of React. However, it was rather fragile because of how the React event system worked.In React components, you usually write event handlers inline:<button onClick={handleClick}>The vanilla DOM equivalent to this code is something like:myButton.addEventListener('click', handleClick);However, for most events, React doesn't actually attach them to the DOM nodes on which you declare them. Instead, React attaches one handler per event type directly at the document node. This is called event delegation. In addition to its performance benefits on large application trees, it also makes it easier to add new features like replaying events.React has been doing event delegation automatically since its first release. When a DOM event fires on the document, React figures out which component to call, and then the React event "bubbles" upwards through your components. But behind the scenes, the native event has already bubbled up to the document level, where React installs its event handlers.However, this is a problem for gradual upgrades.If you have multiple React versions on the page, they all register event handlers at the top. This breaks e.stopPropagation(): if a nested tree has stopped propagation of an event, the outer tree would still receive it. This made it difficult to nest different versions of React. This concern is not hypothetical - for example, the Atom editor ran into this four years ago.This is why we're changing how React attaches events to the DOM under the hood.In React 17, React will no longer attach event handlers at the document level. Instead, it will attach them to the root DOM container into which your React tree is rendered:const rootNode = document.getElementById('root'); ReactDOM.render(<App />, rootNode);In React 16 and earlier, React would do document.addEventListener() for most events. React 17 will call rootNode.addEventListener() under the hood instead.Thanks to this change, it is now safer to embed a React tree managed by one version inside a tree managed by a different React version. Note that for this to work, both of the versions would need to be 17 or higher, which is why upgrading to React 17 is important. In a way, React 17 is a "stepping stone" release that makes next gradual upgrades feasible.This change also makes it easier to embed React into apps built with other technologies. For example, if the outer "shell" of your app is written in jQuery, but the newer code inside of it is written with React, e.stopPropagation() inside the React code would now prevent it from reaching the jQuery code - as you would expect. This also works in the other direction. If you no longer like React and want to rewrite your app - for example, in jQuery - you can start converting the outer shell from React to jQuery without breaking the event propagation.We've confirmed that numerous problems reported over the years on our issue tracker related to integrating React with non-React code have been fixed by the new behavior.Fixing Potential IssuesAs with any breaking change, it is likely some code would need to be adjusted. At Facebook, we had to adjust about 10 modules in total (out of many thousands) to work with this change.For example, if you add manual DOM listeners with document.addEventListener(...), you might expect them to catch all React events. In React 16 and earlier, even if you call e.stopPropagation() in a React event handler, your custom document listeners would still receive them because the native event is already at the document level. With React 17, the propagation would stop (as requested!), so your document handlers would not fire:document.addEventListener('click', function() { // This custom handler will no longer receive clicks // from React components that called e.stopPropagation() });You can fix code like this by converting your listener to use the capture phase. To do this, you can pass { capture: true } as the third argument to document.addEventListener:document.addEventListener('click', function() { // Now this event handler uses the capture phase, // so it receives *all* click events below! }, { capture: true });Note how this strategy is more resilient overall - for example, it will probably fix existing bugs in your code that happen when e.stopPropagation() is called outside of a React event handler. In other words, event propagation in React 17 works closer to the regular DOM.Other Breaking ChangesWe've kept the breaking changes in React 17 to the minimum. For example, it doesn't remove any of the methods that have been deprecated in the previous releases. However, it does include a few other breaking changes that have been relatively safe in our experience. In total, we've had to adjust fewer than 20 out of 100,000+ our components because of them.Aligning with BrowsersWe've made a couple of smaller changes related to the event system:The onScroll event no longer bubbles to prevent common confusion.React onFocus and onBlur events have switched to using the native focusin and focusout events under the hood, which more closely match React's existing behavior and sometimes provide extra information.Capture phase events (e.g. onClickCapture) now use real browser capture phase listeners.These changes align React closer with the browser behavior and improve interoperability.No Event PoolingReact 17 removes the "event pooling" optimization from React. It doesn't improve performance in modern browsers and confuses even experienced React users:function handleChange(e) { setData(data => ({ ...data, // This crashes in React 16 and earlier: text: e.target.value })); }This is because React reused the event objects between different events for performance in old browsers, and set all event fields to null in between them. With React 16 and earlier, you have to call e.persist() to properly use the event, or read the property you need earlier.In React 17, this code works as you would expect. The old event pooling optimization has been fully removed, so you can read the event fields whenever you need them.This is a behavior change, which is why we're marking it as breaking, but in practice we haven't seen it break anything at Facebook. (Maybe it even fix

Read full article »
Est. Annual Revenue
$100K-5.0M
Est. Employees
1-25
CEO Avatar

Founder

Jordan Walke

CEO Approval Rating

- -/100



React's headquarters is located in Menlo Park, California. Jordan Walke is the Founder of React. React has 3 followers on Owler.