I’ve been playing around with React’s new Concurrent Mode and it is amazing. A little mind-bendy, a dash mad, and a whole lot of wonderful.

Your app might get faster even if you don’t change anything. ๐Ÿ‘Œ

That’s because concurrent mode is backwards compatible. Your code works the same … if you’ve been following React best practices. If you haven’t, god help you.

Click through for source

So what is concurrent mode?

It’s a change in how React schedules updates to your UI.

/../ UI libraries, including React, typically work today. Once they start rendering an update, including creating new DOM nodes and running the code inside components, they canโ€™t interrupt this work. Weโ€™ll call this approach โ€œblocking renderingโ€.
In Concurrent Mode, rendering is not blocking. It is interruptible. This improves the user experience. It also unlocks new features that werenโ€™t possible before.

What this means is that you can start new UI updates before the old ones finish.

Say you’re building a dataviz with streaming data. You’re 5,000 elements in so adding another 1,000 takes a while. You start rendering and a new batch shows up before you’re done.

Now what?

With blocking renders you have to wait.

With concurrent mode you stop the current render and schedule a new one. ๐Ÿ‘Œ

It’s similar to how D3 transitions always let you schedule a new transition without worry. Each new transition first stops whatever’s going on, then starts the new transition from current state.

Try clicking this ball real fast to see what I mean

Click through for source

Not quite concurrent mode but a similar idea.

Ok so what?

So what!? This is amazing. This is what we’ve been waiting for for 2 years my friend.

Not only is concurrent mode a big step forward for React itself, it also gives us some new abilities. The community is still figuring out the details, but what I’ve seen buzzing on twitter looks exciting.

My favorite new ability is React Suspense for data fetching. Dan just published an example where he loads code for the page at the same time as its data. And then concurrent mode figures out the rest.

Click through for source

mind_blown giphy

Various react routes will have to implement this to work properly. You can’t quite do it unless you know what data you’ll need before your components render.

That’s the biggest shift in mindset: Fetch data before/while rendering. Not after initial render like we used to:

Click through for source

Dunno about you, but I’m tired of writing that code. Fingers crossed we get some amazing new libraries around Suspense. ๐Ÿคž

While we wait, here’s some concurrent mode stuff you can do right now.

Trying concurrent mode yourself

The easiest way to try concurrent mode is to fire up a CodeSandbox and choose React’s experimental channel.

Same thing works in your package.json. Please don’t use it in production yet. Experiment and play only. There’s bugs to fix and features to come ๐Ÿ™‚

We played around on a recent livestream and created a couple tiny examples using React Suspense’s new fetch-as-you-render ability.

Click through for source

Our context is a D3 scatterplot because a) it looks pretty and b) reactfordataviz.com ๐Ÿ˜›

Don’t worry, if you’re not into dataviz. The same core concepts apply.

We created a fake data streaming API, rendered each unit of data with the new <Suspense /> component, and let React handle the rest. Works great.

Try it out here ๐Ÿ‘‡

CodeSandbox 1

CodeSandbox 2

A fake streaming data API

We split our fake API into two endpoints:

  • fetch a total count
  • fetch datapoints one by one until done

A real world API analog would be an API that deals with large data. First you make a request for some meta data (counts, dates, ranges, etc), then page through the large dataset.

For simplicity and stress testing, we fetch each item individually. Timeouts simulate fetch() calls.

Click through for source

An API that understands

Those function calls simulate API requests. We have to wrap them in a way that <Suspense> understands.

I borrowed the promise wrapper that Dan Abramov uses in official docs on Suspense. You’d build something more robust for real life use. Or, if you’re like me, wait for libraries to show up. ๐Ÿ˜‡

Click through for source

The idea behind wrapPromise is to create a uniform interface for Suspense to hook into your promise. This way it can tell whether it’s still waiting, there was an error, or you’re ready to render.

I imagine this makes it easier to integrate with a variety of data fetching mechanisms. Wrapper makes them conform to Suspense’s API.

Render-as-you-fetch

Once we’ve got the API wrappers set up, we can render our React app in parallel with fetching the data. In some cases even in parallel with fetching the code itself. (code splitting)

Click through for source

We start the request at top level, not inside an effect. This way it starts as soon as the file loads.

Presumably that’s just before you’re ready to render. The approach won’t work if you’re loading 500 pages all in a single bundle and only 1 of them is visible.

Top-level fetching assumes your router handles code splitting and loads only the files it needs.

To render our data without UI glitching, we use the <Suspense> component โœŒ๏ธ

Click through for source

We wrap everything in Suspense to show a loading state while we fetch meta data. The count in our case.

The <DataList> component itself tries to read from our API and render what it gets.

Click through for source

This is important and very easy to get wrong. Suspense goes around the component that’s reading data.

Click through for source

Yeah, happened the very first time I tried to build with React Suspense without following the docs. You get that experiment in your inbox next week, it’s super neat.

Now here’s where it gets real fun: You can nest suspended components.

Notice how we’re wrapping each <DataItem> in its own suspense?

Click through for source

That’s because each item is in charge of its own API fetching. Seems kinda bonkers, but this new approach (also popular in GraphQL circles) is really powerful.

Each React component should take care of its own data fetching. The times when you had a central authority take care of all data are behind us. Edge computing is now. Even if just in our UI tree. ๐Ÿฆพ

Click through for source

Each item hooks into its own index‘d API promise that we created in fetchItem earlier.

items.read() returns an array of wrapped promises. [index] gets the one for this item. .read() waits for that promise to return some data.

The surrounding <Suspense> component handles suspending and fallback renders while this component waits for data to show up. Once data shows up, Suspense renders <DataItem> which uses a little D3 magic to translate [0, 1] numbers to a bigger scale and renders an SVG circle.

mind_blown giphy

Streaming in batches

Now of course reading data one by one like that is slow.

Instead, you can use a paging approach and load a many data points at once. 100 worked pretty well with our fake API.

Rendering code looks the same, just gets an extra loop.

Click through for source

And we changed the fake API to return multiple datapoints per batch.

Click through for source

Fin

I encourage you to give React Suspense and concurrent mode in general a try. It’s pretty great, almost ready for the real world, and it might make you rethink how you structure your apps.

Encouraging you to push data loading into the edges of your component tree seems like a particularly powerful pattern. Load data as close to where you’re using it as possible.

Enjoy โค๏ธ
~Swizec

Learned something new? Want to improve your skills?

Join over 10,000 engineers just like you already improving their skills!

Here's how it works ๐Ÿ‘‡

Leave your email and I'll send you an Interactive Modern JavaScript Cheatsheet ๐Ÿ“–right away. After that you'll get thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over my 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

PS: You should also follow me on twitter ๐Ÿ‘‰ here.
It's where I go to shoot the shit about programming.