Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    Experimenting with the new React Concurrent mode

    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
    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
    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
    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
    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.

    mg9OLOa

    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    Click through for source

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

    Click through for source
    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

    Published on November 6th, 2019 in Front End, Livecoding, Technical

    Did you enjoy this article?

    Continue reading about Experimenting with the new React Concurrent mode

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️