What's New in React 16+?
If you're more than one major release behind in React, your upgrade clock is ticking... - Me
If you're not yet on React 16, you're probably beginning to notice your libraries and their dependencies are increasingly objecting to one another. You're able to deal with these nuances on an as-needed basis for now but unfortunately, you're eventually going to run out of workarounds.
I know upgrades suck. They don't move the needle with regards to your product roadmap but take the time now so you can move faster in the future. It will all come out in the wash, I promise you.
Check out my list of what you get with React 16 as well as the deprecations and breaking changes you might run into as you go through this migration. This isn't a ground-breaking article but I'm in the thick of this right now @lumenad and thought notes/snippets from my research might help someone else embarking on this journey.
Oh and hey, good luck!
Lifecycle Methods reference
One of the biggest lessons React learned was that some of their legacy component lifecycles tend to encourage unsafe coding practices. You'll be able to use the below lifecycle methods in React 16 and 17 but now is a good time to prep your team for migrating off of them in the near future.
They lifecycle methods being deprecated are:
- componentWillMount (rename to UNSAFE_componentWillMount)
- componentWillReceiveProps (rename to UNSAFE_componentWillReceiveProps)
- componentWillUpdate (rename to UNSAFE_componentWillUpdate)
getDerivedStateFromProps (new)
This method is going to handle what componentWillReceiveProps was able to do along with componentDidUpdate. It is static. It is called after a component is created and also called when it receives a new prop. This will be the safer alternative to componentWillReceiveProps.
getSnapshotBeforeUpdate (new)
This method is going to handle what componentWillUpdate was able to do along with componentDidUpdate. This is called right before the DOM is updated. The value that is returned from getSnapshotBeforeUpdate is passed on to componentDidUpdate.
componentDidUpdate is called as soon as the DOM is updated. The snapshot value is passed on to componentDidUpdate.
Strict Mode Tool reference
In addition to the lifecycle method changes, React has released a new tool called Strict Mode. It identifies and highlights unsafe lifecycle methods in components, and many other side-effects during development. Begin using it after your upgrade is complete.
Error Boundary reference
Previously, runtime errors during rendering could put React in a broken state. With React 16, instead of unmounting the whole app every time there’s an error, you can use error boundaries. Error boundaries are analogous to try{ }catch(e){ } statements, but live inside and are scoped by component hierarchy instead of inside a given block of synchronous javascript.
Instead of unmounting the whole app every time there’s an error, you can use error boundaries. Error boundaries are special components that capture errors inside their subtree and display a fallback UI in its place. Think of error boundaries like try-catch statements, but for React components.
Fragments, Hallelujah! reference
React 16.0 added support for returning an array of elements from a component’s render. Instead of wrapping the children in a DOM element, you can put them into an array. This prevents adding additional div or span in DOM from each component that returns multiple element.
With React 16.2 the biggest addition is improved support for returning multiple children from a component’s render method. The feature is called Fragments. Fragments look like empty JSX tags. They let you group a list of children without adding extra nodes to the DOM:
You can use <Fragment /> the same way you’d use any other element, without changing the way you write JSX. No commas, no keys, no quotes.
Keyed Fragments: Note that the <></> syntax does not accept attributes, including keys. If you need a keyed fragment, you can use directly. A use case for this is mapping a collection to an array of fragments — for example, to create a description list
Support for JSX fragments is available in Babel v7.0.0-beta.31 and above. If you are using Babel with Webpack, no additional steps are needed because babel-loader will use your peer-installed version of Babel.
Portals reference
Render items into a new DOM node. A typical use case for portals is when a parent component has an overflow: hidden or z-index style, but you need the child to visually “break out” of its container. For example, dialogs and tooltips. The main advantage is it follows event delegation as per your React tree node even though it is part of a different node.
Better server-side rendering reference
React 16 includes a completely rewritten server renderer. It’s really fast. It supports streaming, so you can start sending bytes to the client faster.
Is better at hydrating server-rendered HTML once it reaches the client. It no longer requires the initial render to exactly match the result from the server. Instead, it will attempt to reuse as much of the existing DOM as possible. No more checksums! In general, we don’t recommend that you render different content on the client versus the server, but it can be useful in some cases (e.g. timestamps). However, it’s dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.
According to Sasha’s synthetic benchmarks, server rendering in React 16 is roughly three times faster than React 15.
Support for custom DOM attributes reference
Instead of ignoring unrecognized HTML and SVG attributes, React will now pass them through to the DOM. This has the added benefit of allowing us to get rid of most of React’s attribute whitelist, resulting in reduced file sizes.
Deprecations
- Hydrating a server-rendered container now has an explicit API. If you’re reviving server-rendered HTML, use ReactDOM.hydrate instead of ReactDOM.render. Keep using ReactDOM.render if you’re just doing client-side rendering.
- Support for React Addons has been discontinued.
- createFragment, to create a set of externally-keyed children.
- Perf, a performance profiling tool for finding optimization opportunities.
- ReactTestUtils, simple helpers for writing test cases.
- react-addons-perf no longer works in React 16. In the meantime, we can use Chrome's performance audity tools to profile React components.
- PureRenderMixin. Use React.PureComponent instead.
- shallowCompare, a helper function that performs a shallow comparison for props and state in a component to decide if a component should update. We recommend using React.PureComponent instead.
- update. Use kolodny/immutability-helper instead.
- ReactDOMFactories, pre-configured DOM factories to make React easier to use without JSX.
- LinkedStateMixin has been deprecated.
- TransitionGroup and CSSTransitionGroup have been deprecated in favor of their drop-in replacements.
In React 16.3, they add these new deprecated names as optional.
- UNSAFE_componentWillMount
- UNSAFE_componentWillRecieveProps
- UNSAFE_componentWillUpdate
- In React 17, you will be forced to rename them to the above.
Html Attributes
In React 16, HTML attributes are more strict.
- Before, if you had a boolean attribute on an HTML element, it would convert a JavaScript boolean value to a string value. With React 16, you must pass a string value.
- With React 15, you could set aria-require={false}.
- With React 16, you would want to set that as aria-required="false"
boolean onClick
React 16 will warn about getting a boolean onClick value, which can happen if you do onClick ?={!disabled && this.handleOnClick}. Handle the disabled state inside the function to resolve.
Breaking Changes Migrating to React 16.8.6
React 15 had limited, undocumented support for error boundaries using unstable_handleError. This method has been renamed to componentDidCatch. You can use a codemod to automatically migrate to the new API.
ReactDOM.render and ReactDOM.unstable_renderSubtreeIntoContainer now return null if called from inside a lifecycle method. To work around this, you can use portals or refs.
setState:
- Calling setState with null no longer triggers an update. This allows you to decide in an updater function if you want to re-render.
- Calling setState directly in render always causes an update. This was not previously the case. Regardless, you should not be calling setState from render.
- setState callbacks (second argument) now fire immediately after componentDidMount / componentDidUpdate instead of after all components have rendered.
When replacing <A /> with <B />, B.componentWillMount now always happens before A.componentWillUnmount. Previously, A.componentWillUnmount could fire first in some cases.
Previously, changing the ref to a component would always detach the ref before that component’s render is called. Now, we change the ref later, when applying the changes to the DOM.
It is not safe to re-render into a container that was modified by something other than React. This worked previously in some cases but was never supported. We now emit a warning in this case. Instead you should clean up your component trees using ReactDOM.unmountComponentAtNode.
componentDidUpdate lifecycle no longer receives prevContext param.
Shallow renderer no longer calls componentDidUpdate because DOM refs are not available. This also makes it consistent with componentDidMount (which does not get called in previous versions either).
Shallow renderer does not implement unstable_batchedUpdates anymore.
ReactDOM.unstable_batchedUpdates now only takes one extra argument after the callback.
In my next article, I'll show the steps we took to perform our upgrade. But first, I need to finish it. Gotta go!