As of this writing, Concurrent mode is experimental. It allows the rendering process interruptible. It doesn’t block the browser from making changes to the DOM and continues rendering in memory.
Before this, Suspense was used for waiting for some code to load (like a spinner). But now, it is used for data fetching, scripts, images, etc. It waits for content to load and then update the UI.
Once they start rendering an update, including creating new DOM nodes and running the code inside components, they cannot interrupt this work. We’ll call this approach “blocking rendering”.
In Concurrent Mode, rendering is not blocking. It is interruptible, and it improves the user experience. It also unlocks new features that weren’t possible before.
Modes
- Legacy Mode:
- ReactDOM.render(
, rootNode). This is what React apps use today. There are no plans to remove the legacy mode in the observable future — but it won’t be able to support these new features. - Blocking Mode:
- ReactDOM.createBlockingRoot(rootNode).render(
). It is currently experimental. It is intended as a first migration step for apps that want to get a subset of Concurrent Mode features. - Concurrent Mode:
- ReactDOM.createRoot(rootNode).render(
). It is currently experimental. In the future, after it stabilizes, we intend to make it the default React mode. This mode enables all the new features.
Installation
npm install react@experimental react-dom@experimental
Enabling Concurrent Mode
createRoot
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
Above enables the concurrent mode.
createBlockingRoot
ReactDOM.createBlockingRoot(document.getElementById('root')).render(<App />);
Above enables the blocking mode.
You can not migrate your app directly to concurrent mode, as it introduces semantic changes to react.
Suspense API
Suspense
Suspense
lets your components “wait” for something before they can render, showing a fallback while waiting.
<Suspense fallback={<h1>Loading...</h1>}>
<Photo />
</Suspense>
<SuspenseList>
SuspenseList helps coordinate many components that can suspend by arranging the order in which these components are revealed to the user.
<SuspenseList revealOrder="forwards">
<Suspense fallback={'Loading...'}>
<Photo id={1} />
</Suspense>
<Suspense fallback={'Loading...'}>
<Photo id={2} />
</Suspense>
...
</SuspenseList>
useTransition
useTransition allows components to avoid undesirable loading states by waiting for content to load before transitioning to the next screen. It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.
const [startTransition, isPending] = useTransition({ timeoutMs: 2000 });
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
setResource(fetchData(next));
});
}}
>
</button>
useDeferredValue
This can be used to keep the application responsive when you have something to render like user input or fetch data. The deferred value is allowed to lag behind.
const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });