The Evolution of React: V16 and Beyond
Cameron Wilson
Posted on November 14, 2019
Originally posted on Educative.io
React has changed quite a bit since its recent updates. While the fundamentals are essentially the same, the way we write and address React apps has changed. Even if you’ve mastered React in the past, you may not be totally up to date with its new features.
Keeping your React knowledge relevant can feel like an uphill battle. Where do you start? How important are these features for your day-to-day use? What even is a hook anyway and why would I use it over HoCs and render props?
React expert, Ohans Emmanuel, has taken all the major features of modern React and built an interactive, hands-on course so you can stay in sync with the most recent changes while learning to write better software. Get started with Reintroducing React: V16 and Beyond.
Without further ado, let’s walk through a brief summary of the updates to React since the release of Version 16.
Here is what we’ll be going over today:
- New Lifecycle Methods
- Simpler State Management with the Context API
- ContextType - Using Context without a Consumer
- React.memo
- The Profiler
- Lazy Loading with React.Lazy and Suspense
- React Hooks
New Lifecycle Methods
A lifecycle in React is the series of changes that a component undergoes. The four essential lifecycle phases attributed to a React component include:
- Mounting — This is the beginning phase where the component is created and then inserted into the DOM.
- Updating — This is the phase where a React component undergoes growth by being updated via changes in props or state.
- Unmounting — This is the phase where the component is removed from the DOM.
- Error Handling — This is the phase when there is a problem with your component, like a bug. When this happens, the component is in the error handling phase.
In React, Lifecycle Methods are invoked during these various phases. A few React methods have been replaced by new lifecycle methods. React still supports componentWillMount
, componentWillUpdate
, and componentWillReceiveProps
, but using them going forward will not be the best practice. Instead, you should now use these additions:
1) static getDerivedStateFromProps
: This is invoked before calling the render method during the initial mounting phase. It will return either an object that updates the state, or null to make no updates.
There are two common use cases:
- (during mount) to return a state object based on the initial props
- to update state based on props, when the props themselves aren’t enough.
2) getSnapshotBeforeUpdate
: This lifecycle method is invoked right after render, or immediately before your most recent output is committed to the DOM. This method is useful when you need to grab information from the DOM just after an update is made. This method is typically used in conjunction with componentDidUpdate
.
A common use case is taking a look at some attribute of the current DOM, and passing that value on to componentDidUpdate
.
3) static getDerivedStateFromError
: This lifecycle method is used to update the state of your React app. Whenever an error is thrown in a descendant component, this method is called first, and the error thrown is passed as an argument. Whatever value is returned from this method is used to update the state of the component.
A common use case is updating state to display an error screen.
4) componentDidCatch
: This lifecycle is invoked after an error has been thrown out by using two parameters, info
(an object stating which component threw the error) and error
(the discarded error). It is invoked during the commit phase. You can update the ErrorBoundary
component to use this lifecycle method.
A common use case is starting AJAX calls to load in data for your component.
A note on the
ErrorBoundary
component: These will catch and log JavaScript errors present in their child component tree during the render phase. You can update theErrorBoundary
component to use thecomponentDidCatch
method.
Simpler State Management with Context API
Passing props down through a deeply nested component tree can be challenging. There’s a new, simple solution, and it’s not Redux or MobX, The Context API is a simple, native way to pass down props through a deeply nested component tree, making it possible to share state data that is considered “global” within a component tree. You can now stop passing props through intermediate elements.
This new feature is most useful if you’re passing props through more than three levels in your component tree.
To use this feature, you create a context object using React.createContext( )
. You have to then create a wrapper component that returns a Provider component. Since the Provider
provides the values saved in the context object, we can wrap a tree of components with the Provider. Now, any child component within the Root can access state values and the corresponding updated functions.
<provider>
// the root component
<Root />
</Provider>
ContextType - Using Context Without a Consumer
Context is used primarily when data needs to be accessed by multiple components at different nesting levels. This new React update tries to solve the problem of nesting when it becomes cumbersome to pass certain types of data. Now, you can consume data from context without directly using the Consumer
component. In other words, the contextType
class property enables you to get rid of the Consumer
component for certain cases.
Note that you can only use one contextType
within a class
component, so you will have to use nested code if you introduce multiple Consumers
.
To do so, you set the contextType
property of the class component to a context object. You can then consume values from that context object using this.context
. This way, you don’t have to nest data!
React.memo
The new React.memo
is used for controlling when components render. It replaces the PureComponent
. You use it to wrap functional components, and you get the exact same results as the PureComponent
function.
React.memo
is a higher order function, so, if props don’t change, react will skip rendering the component to favor the previously memorized value. To handle this, React.memo
takes in the equalityCheck
function as an argument. If it returns true
, there will be no re-render, and if it returns false
, there will be a re-render. If you use this function, you need to include checks for function props, otherwise you may get bugs.
import React, { memo } from 'react'
export default memo(function MyComponent ({name}) {
return ( <div>
Hello {name}.
</div>
)
})
The Profiler: Collecting Data for Better React Apps
The Profiler is a replacement for the react-addons-perf
module, which is no longer supported by React 16. The Profiler helps with rendering times and bottlenecks by measuring performance and identifying render times. The Profiler records a session of your app and gathers information about the various components in two phases: the render phase and the commit phase. It then displays results about these two phases which you can learn to interpret to make useful changes to your apps.
You gather profiling data by clicking the record button and interacting with different facets of your application. This will generate the Flamegraph Tab, which shows you the components you used and the different render times. The Profiler can also rank data and compare it across multiple renders of the same application. Using this data, you can resolve performance leaks by adding Profiler
anywhere in your React tree.
To access the Profiler, you need React v16.5.0+ and React Developer Tools
Lazy Loading with React.lazy and Suspense
This new feature enables you to handle lazy loading without relying on third-party libraries. It can be used to improve performance on your React apps. Bundling code in progression can get very cumbersome, and this slows down your app. With code splitting, you can split your code into chunks and load the critical user interface items before the non-critical ones.
Using React.lazy()
, you can use code splitting to load React components lazily. Suspense
is required to wrap multiple lazy components and control user experience even as the items are being loaded into the DOM. These two features make dynamic imports much easier.
It’s important to wrap your lazy-loaded components in an error boundary, otherwise there may be a network error during fetching. Also, note that React.lazy
and Suspense
do not yet support server-side rendering or named exports.
React Hooks: For Simpler React Apps
And now what you’ve been waiting for! React Hooks. Hooks were released in React 16.8.0. With hooks, you can “hook into” state and lifecycle features from within function components. This is a powerful way to share functionality between components instead of using class components.
With hooks, you can share logic inside a component. Now you’re able to write clean, reusable code and create stateful components without the use of class. There are several built-in hooks that all begin with the word use
. Let’s briefly go over a few notable ones.
For more on hooks, check out our blog post on React Design Patterns or React’s Hooks API Reference Sheet
Or, for a basic tutorial on how to build a TODO list with hooks you can visit this post
useState
: This hook enables your functional component to use and update local state. It is called inside a function component to add local state to it. It then returns the current state value and a function that lets you update it. This hook can be used more than once in a single component. It’s similar tothis.setState
in a class, but it doesn’t merge the old and new state together.useEffect
: With this hook, you can perform side effects from a function component unified as a single API. This is similar to the classcomponentDidMount
. React runs the effect function after each render.useContext
: With this hook, you can subscribe to React context without nesting.useReducer
: With this hook, you can work with local state of complex components and avoid using a reducer.Custom Hooks: You can also make your own hooks to serve different purposes by using the
use
keyword. There are two rules to follow: you can only call hooks at the Top Level, and you can only call hooks from React functions.
Tip: If you want to build your own hooks, the ESLint plugin will make sure you stick to the rules.
Get to Learning!
Clearly, there is a lot to learn to stay in sync with React. We don’t want you to fall behind. That’s why we’ve released our new Reintroducing React: V16 and Beyond course. While you can still work around some of these new updates, they will quickly become the preferred method for creating React apps, so it’s best to learn how to work with these features now.
This course will get you up to speed to ensure you’re using your full React potential. It’s loaded with visuals, quizzes, and code playgrounds so you can test out the new features as you learn. By learning how to work with modern React, you’ll evolve the way you develop React apps while making use of powerful features that will make you a better developer.
Happy learning!
Posted on November 14, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.