Time slice and Suspense API: What’s coming in React 17?

time-slice-suspense-api-react-17-header.png

An overview of two new pieces of functionality in React 17: time slice and suspense. These are intended to improve performance and better support low end devices.

Introduction

React powers so many awesome web and mobile apps such as Whatsapp, Instagram, Dropbox, and Twitter. Along the road, React had to make some tough changes, an example is the migration from the difficult BSD + Patents license to the very non-restrictive MIT license following the decision by the Apache Foundation to ban the use of React. The change proved to be a key decision as not only did it bring more developers to React, it led a number of key projects such as WordPress and Drupal to adopt React. In this tutorial, we will explore what’s new in React 17 along with Time Slice and Suspense API.

What’s new in React 17?

The Fiber rewrite that subsequently led to the release of React 16.0 came with changes such as Error boundaries, improved server-side rendering, fragments and portals just to mention a few (learn more).

However, React 17 comes with even more exciting features. At a JavaScript conference in Iceland, JSConf 2018, the creator of Redux and a core team member of React, Dan Abramov, demoed the new features that would be present in React 17. In React’s latest release, a few factors that were addressed include:

  • How network speed affects the loading state of your application and in the larger picture – user experience.
  • How the state of your application is managed on low-end devices.

Time Slice

Early on in the development process of React 16.0, asynchronous rendering was kept off due to potential backward compatibility issues. Although it enables faster response in UI rendering, it also introduces challenges for keeping track of changes in the UI. That’s where time slicing comes in. In the words of Dan:

Time slice was created to make asynchronous rendering easier for developers. Heavy React UIs on devices with “not so great” CPU power could make users experience a “slow” feel when navigating through the app.

With time slicing, React can now split computations of updates on children components into chunks during idle callbacks and rendering work is spread out over multiple frames. This enhances UI responsiveness on slower devices. Time slice does a great job in handling all the difficult CPU scheduling tasks under the hood without developer considerations.

Suspense

Wouldn’t it be great if your app could pause any state update while loading asynchronous data? Well, that’s one of the awesome features of suspense.

1“Suspense  provides an all-encompassing medium for components to suspend 
2         rendering while they load asynchronous data.”

Suspense takes asynchronous IO in React to a whole new level. With the suspense feature, ReactJS can temporarily suspend any state update until the data is ready while executing other important tasks. This feature makes working with asynchronous IO operators such as calling REST APIs like Falcor or GraphQL much more seamless and easier.

Developers can now manage different states all at once while users still get to experience the app regardless of network speed – instead of displaying only loading spinners, certain parts of the app can be displayed while other parts load thus ensuring that the app stays accessible. In many ways, suspense makes Redux, the state management library appear even more defunct.

Suspense lets you *delay* rendering the content for a few seconds until the whole tree is ready. It *doesn’t* destroy the previous view while this is happening.

— Dan Abramov (@dan_abramov) March 4, 2018

While Dan was demonstrating how suspense works, he used an API called createFetcher. createFetcher can be described as a basic cache system that allows React to suspend the data fetching request from within the render method. A core member of the React team, Andrew Clark, made it clear what to expect from createFetcher:

createFetcher from @dan_abramov's talk is this thing:

We're calling it simple-cache-provider (for now). It's a basic cache that works for 80% of use cases, and (when it's done) will serve as a reference implementation for Apollo, Relay, etc.https://t.co/elI6YFco0A

— Andrew Clark (@acdlite) March 1, 2018

Note: It must be noted that the createFetcher API is extremely unstable and may change at any time. Refrain from using it in real applications. You can follow up on its development and progress on Github.

To show you how suspense works, I’d like to adopt excerpts from Dan’s IO demo at JSConf 2018:

1import { createFetcher, Placeholder, Loading } from '../future';

In the image above, the createFetcher API imported from the future has a .read method and will serve as a cache. It is where we will pass in the function fetchMovieDetails which returns a promise.

In MovieDetails, a value is read from the cache. If the value is already cached, the render continues like normal else the cache throws a promise. When the promise resolves, React continues from where it left off. The cache is then shared throughout the React tree using the new context API.

Usually, components get cached from context. This implies that while testing, it’s possible to use fake caches to mock out any network requests. createFetcher uses simple-cache-provider to suspend the request from within the render method thus enabling us to begin rendering before all the data has returned.

simple-cache-provider has a .preload method that we can use to initiate a request before React gets to the component that needs it. Let’s say in an e-commerce app you’re switching from ProductReview to Product, but only ProductInfo needs some data. React can still render Product while the data for ProductInfo is being fetched.

Suspense enables the app to be fully interactive while fetching data. Fears of race conditions occurring on the app while a user clicks around and triggers different actions are totally quashed. In the picture above, using the Placeholder component, if the Movie review takes more than one second to load while waiting for async dependencies, React will show the spinner.

We can pause any state update until the data is ready and then add async loading to any component deep in the tree. This is possible through the Loading component which renders a prop called isLoading that lets us decide what to show.

Note: Loading is part of the simple-cache-provider . Chances are, just like every name or API that has been proposed, there might be breaking changes in future ReactJS releases. Ensure you refrain from using this in real applications.

Summary

With time slice we can handle all our arduous CPU scheduling tasks under the hood without any considerations. With suspense, we solve all our async race conditions in one stroke. A brief recap of the points noted by Dan at JSConf 2018:

While you’re at it you can also watch Dan’s full presentation at JSConf 2018 where he gave detailed reasons behind the new features in React 17, most notably CPU and I/O optimizations.