When to Avoid Concurrent Mode in React
React’s concurrent features introduce powerful ways to improve application responsiveness by allowing React to interrupt, pause, and resume rendering. However, opting into concurrent rendering is not always beneficial and can sometimes introduce bugs, performance regressions, or architectural complexity. This article outlines the specific scenarios where you should avoid using Concurrent Mode and concurrent features in your React applications.
1. When Using Incompatible Third-Party Libraries
Concurrent rendering can pause and resume the rendering process,
which means the render phase can run multiple times before the UI
actually updates. Many older or poorly maintained third-party libraries
rely on synchronous, uninterrupted rendering. If a library mutates
external state during the render phase, or relies on legacy lifecycle
methods like componentWillMount, enabling concurrent
features will cause UI bugs, memory leaks, or application crashes.
2. When Your State Managers Do Not Support “Tearing” Prevention
“Tearing” occurs when different parts of the UI render using
different versions of the same external state, resulting in a visually
inconsistent interface. This happens because React can pause rendering,
allow an external store to update, and then resume rendering. If you are
using older state management libraries that have not been updated with
useSyncExternalStore, you should avoid concurrent features
until you can upgrade your state management architecture.
3. For Simple, Static, or Low-Interaction Applications
Concurrent Mode is designed to solve complex UI responsiveness issues, such as heavy data filtering, complex animations, or slow network transitions. If your application consists primarily of static pages, simple forms, or low-intensity interactions, the overhead of concurrent rendering outweighs the benefits. Implementing transition hooks or deferred values in these cases adds unnecessary code complexity without any visible performance gain.
4. When Managing Highly Sensitive Controlled Inputs
Controlled inputs (like text fields) require immediate, synchronous
updates to ensure that the user’s keystrokes are registered and
displayed without lag or cursor-jumping. Attempting to use concurrent
features like useTransition or
useDeferredValue directly on the state governing a text
input’s value can lead to input lag, dropped characters, and a
frustrating user experience. Input states should almost always remain
synchronous.
5. When Dealing with CPU-Heavy Calculations That Can Be Optimized Elsewhere
While concurrent features prevent the UI from freezing during heavy
rendering, they do not make slow JavaScript code run faster. If your
application is slow due to heavy data processing or expensive
algorithms, relying on Concurrent Mode is a band-aid solution. Instead
of deferring the slow render, you should optimize the raw JavaScript,
memoize the calculations using useMemo, or offload the
heavy computations to a Web Worker.