Trying out React 18 Alpha

React 18 is here! That's the one with concurrent mode πŸ₯³

Well, it's almost here. You can play with experimental code, check out the working group, and hope library authors update soon.

The gist is that:

  1. You don't gotta upgrade
  2. New features are opt-in
  3. React 16/17 and React 18 code can work together on the same screen
  4. Typical apps can "update in an afternoon"
  5. Library authors might have work to do
  6. Useful Suspense comes later

I've been waiting for this since Experimenting with the new React Concurrent mode in November 2019 and Time Slicing for visualizing large datasets in September 2018. I even tried to get Gatsby working with Suspense in 2019, but that was clunky.

Happy Jeff Goldblum GIF by Apartments.com

The goods

Biggest update from the UI perspective is the new/better render batching for fewer updates. Reduces DOM writes, increases performance.

React 17 batches updates in event handlers. React 18 will batch updates every time.

function Component() {
  const [boop, setBoop] = useState(2)
  const [booper, setBooper] = useState(3)

  // 2 re-renders
  function onClick() {
    fetch().then(() => {
      setBoop(3)
      setBooper(4)
    })
  }

  // 1 re-render
  function onClick() {
    setBoop(3)
    setBooper(4)
  }
}

When you opt into React 18 features, both those cases trigger 1 component re-render. Your UI becomes faster and more responsive with no extra work 🀘

ServerSideRendering gets a new streaming mode and easier-to-use hydration support. This one's for folks like Gatsby and NextJS. Or if you were brave enough to roll your own.

A good lesson in Not Invented Here. Leave the fiddly stuff to the fiddlers.

Suspense gets a behavior update that makes it easier to understand.

<Suspense fallback={<Loading />}>
  <ComponentThatSuspends />
  <Sibling />
</Suspense>

The point of <Suspense> is to enable loading modes in your UI. Instead of {isLoading && <Component>}, you can let React handle that for you.

Fantastic when different components have to coordinate their loading – lets you avoid spinner cascades. They suck.

With React 17, that <Sibling> component would mount, run its effects, then hide. Now it waits until data is ready. As I think it always should have.

More to come in 18.x updates.

Concurrent features

A gaggle of exciting new APIs that let you tell React "Hey this update is less important, do it later"

Fantastic for large re-draws, data visualization, and anywhere your app feels a little janky right now. I've got this issue in production where you click a button and we redraw 300 components with 10 complex hooks each.

This will help.

Happy Jeff Goldblum GIF by Apartments.com

startTransition lets you mark an update as a transition. You could hack this with time slicing – setTimeout – but that's a delay and may lag. startTransition is synchronous.

useDeferredValue lets you update state with a delay.

The new <SuspenseList> allows you to coordinate how loading spinners cascade. This will become more useful in 18.x versions.

The new streaming SSR API with partial hydration lets you hydrate parts of the app while the rest loads. Make above-the-fold instantly interactive, let the rest load later 🀞

How to opt-in

You'll want to install React from the latest alpha tag.

yarn add react@alpha react-dom@alpha

Expect broken-ness, changing APIs, and shifting details. When they say Alpha, they mean it.

A change to the root opts you in:

const root = ReactDOM.createRoot(container)
root.render(<App />)

Anything below <App /> has access to the new features. You can use this alongside the old ReactDOM.render(<App />, container); API.

Read more details about how root changes on the working group pages.

Let's try it out

Now the fun part, can you see a difference?

We put React 18 to the test with an old computer science and mathematics game – a random walk, sometimes called The Drunkard's Walk. The math is fun, the visuals are better.

Observe, in React 17:

At first all is well.

But the code is designed to be naive and inefficient. As the walk grows longer, each re-draw takes longer and longer. Adding steps slows down because we copy arrays.

With luck, you'll see this lag as you type in the input field.

Now try it out in React 18:

Can you see the difference?

I felt typing was smoother and animation was more jagged. As expected. Might be placebo? Always hard to tell.

Read the comments to learn how it works. ✌️

Cheers,
~Swizec