React Fiber (React v16) is awesome and has taken some significant steps towards improving the developer experience as well as the quality of applications built with React. In this post, we will look at how React 17 looks to build on React v16.
Why asynchronous rendering?
With a strong focus on asynchronous rendering, React 17 looks to create an environment for developers to build efficient applications easily by making it possible to minimize the impact of computing and network speeds on the user experience.
To achieve this, there will inevitably be some shift in the way React apps are written through the introduction of some new features and deprecation of some previous ones.
Here are the changes we can expect:
- Introduction of new lifecycle methods
- Time slicing
- Suspense
Let’s look at them one by one.
New lifecycle methods
Replacing the deprecated lifecycle methods are two new lifecycle methods, getDerivedStateFromProps
and getSnapShotBeforeUpdate
.
These are essential to keep in mind if you are preparing to migrate your application to React 17. A great starting point is replacing the unsafe methods with these new lifecycle methods. For instance, componentWillUpdate
can be replaced by using getDerivedStateFromProps
in conjunction with shouldComponentUpdate
, componentWillMount
should be removed altogether for async rendering.
Here’s a diagram of what the component lifecycle will look like after React v16.4 with the unsafe methods removed.
getDerivedStateFromProps
This lifecycle method replaces componentWillReceiveProps
and componentWillUpdate
and will be called after a component is created and when it received new props. It returns an object to update state when props change or null
when there is no change in state.
state = { cachedSomeProp: null }; static getDerivedStateFromProps(nextProps, prevState) { // do things with nextProps.someProp and prevState.cachedSomeProp return { cachedSomeProp: nextProps.someProp, .. }; }
However, keep in mind that this lifecycle method is only meant to be used in cases where a component needs to update its local state following a change in props. Unnecessary use of this method may introduce some bugs such as unconditionally copying props to state and erasing state when props change as was the case with componentWillReceiveProps
.
getSnapshotBeforeUpdate
This handles component updates and will effectively replace componentWillUpdate
and works with componentDidUpdate
. It is called before any DOM updates and returns a value that is passed to componentDidUpdate
which then handles the changes:
class ScrollingList extends React.Component { listRef = null; getSnapshotBeforeUpdate(prevProps, prevState) { // Are we adding new items to the list? // Capture the scroll position so we can adjust scroll later. if (prevProps.list.length < this.props.list.length) { return ( this.listRef.scrollHeight - this.listRef.scrollTop ); } return null; } componentDidUpdate(prevProps, prevState, snapshot) { // If we have a snapshot value, we've just added new items. // Adjust scroll so these new items don't push the old ones out of view. // (snapshot here is the value returned from getSnapshotBeforeUpdate) if (snapshot !== null) { this.listRef.scrollTop = this.listRef.scrollHeight - snapshot; } } render() { return ( <div ref={this.setListRef}> {/* ...contents... */} </div> ); } setListRef = ref => { this.listRef = ref; }; }
Time slicing
Time slicing is the biggest update to React that looks to improve user experience. It aims to make sites more friendly by allowing prioritized rendering of elements. So high priority updates aren’t blocked because of rendering low priority updates.
Dan Abramov likened this to version control at JSConf Iceland 2018. Where work is split into branches and the work of each branch is merged to master once complete. Similarly, with time slice, elements can be rendered separately allowing the app to have ready elements rendered and a placeholder for elements yet to be rendered.
A good example is a case where we are fetching users’ details. The user avatar and name will display and their bio comes in later. Time slice will allow us to display the ready details(name and avatar) and have a placeholder while the bio is fetched. Once the bio is ready it renders and the final state is as expected. This enhances the responsiveness of the app on slower devices and networks and also means the rest of the app can still be used while a certain element is still rendering.
How is this achieved? Through a new API called Suspense that was introduced in React 16.6.
Suspense
Suspense is responsible for rendering the fallback UI(placeholder) while state updates are being prepared. It holds back rendering of the final UI until these updates are ready, rendering a placeholder of your choice in the meantime. This is where you would place your spinner if that’s what you plan to use to indicate a loading state.
This provides a great alternative to conditional rendering to handling data loading. You can also set a time limit and if the data loads within this time the fallback UI will not be rendered in concurrent mode. Awesome, right? Even better, Suspense was introduced in React 16.6, so Suspense is ready to use right now.
Here’s a simple example of Suspense in use:
const DataComponent = React.lazy(() => import('./DataComponent')); function MySuspenseComponent(){ return ( <Suspense fallback={<Spinner />}> <DataComponnent/> <Suspense> ) }
In the above example, Suspense is used in conjunction with lazy() which lazy loads the DataComponent, while the component is loading, a spinner will display and our component only shows up after loading is complete. We can also do this using other async operations such as API calls.
Also expected with React 17 is a stable version of the react-cache library which will help expand on the functionality of Suspense and allow the use of async operations with synchronous operations. Here’s what react-cache may look like:
const getInfo = () => fetch("https://myApi.apiexample").then(res => res.json()) const ApiResource = createResource(getInfo) const SayHello = () => { const data = ApiResource.read() return <div>Hi {data.name}</div> } const App = () => ( <Suspense fallback={<Spinner />}> <SayHello /> </Suspense> )
The react-cache may also be used with time slicing to load data in the background as a low priority update, a good example is when displaying data as tabs, this makes the data instantly available when switching between tabs. Andrew Clark gave a great demo of such as a use case at React Conf 2018, check it out below:
Conclusion
React 17 is a major release with several reasons for React developers to get excited. Not only does it provide some amazing, new features that will redefine how React applications are built, but it also expands on recently introduced features such as Hooks with incremental changes that allow developers to make better use of them. This will lead to better applications and a better experience building them. It is exciting to see what else the future holds for React.
You may also want to check out Dan Abramov’s talk at JS Conf 2018 which I referred to when compiling this article.
LogRocket: Full visibility into your production React apps
Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?
Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.
No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.