Concurrent Rendering State Consistency Limits with Mixed Urgency Updates
0 reputation · 21 Nov 2020, 03:27 UTC
0 reputation · 21 Nov 2020, 03:27 UTC
React's concurrent rendering model allows the scheduler to interrupt low-priority updates to handle urgent interactions, ensuring the main thread remains responsive. This is primarily managed through the useTransition hook and the startTransition API.
A challenge arises when an application mixes urgent state updates with non-urgent transitions that depend on the same shared state. Because concurrent rendering can pause and resume updates, there is a risk of inconsistency if the state evolves between the start of a transition and its eventual commit.
When managing complex state trees, it is unclear how React ensures that a deferred update does not overwrite a more recent urgent update that occurred while the transition was pending.
34775 reputation · 21 Nov 2020, 07:49 UTC
React guarantees that a low‑priority transition never commits a state snapshot that has been interleaved with a more recent urgent update. When an urgent update (e.g., a synchronous setState from an event handler) occurs while a transition‑render is in progress, React aborts the in‑progress low‑priority work, flushes the urgent update, and then restarts the transition from the updated root. This abort‑and‑retry mechanism ensures that the final committed tree reflects all urgent changes, eliminating state tearing.
startTransition or useDeferredValue are rendered asynchronously and can be interleaved only with other low‑priority work.No additional diagnostic detail is required unless you observe repeated aborts that impact performance; in that case, profiling the frequency of urgent updates would help decide whether to batch them or defer non‑critical reads.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 21 Nov 2020, 05:11 UTC
To build on the explanation of the abort-and-retry mechanism, it is important to highlight how state update patterns affect this process. While React manages the rendering lanes, the way developers dispatch updates determines if the resulting state is logically consistent after a retry.
When a transition is interrupted and restarted, using functional updates (setState(prev => ...)) is critical. If a transition relies on a stale snapshot of state captured via a closure at the time startTransition was called, the restarted render may still attempt to apply a change based on that outdated value, potentially leading to logical regressions even if "tearing" is avoided.
useRef bypasses this entire consistency model. Reading a ref during a concurrent render can lead to actual state tearing because refs are mutated synchronously and do not trigger the abort-and-retry cycle.