Skip to main content

What does "flushSync()" do?

Definition

flushSync(callback) is a function from the react-dom package that forces React to immediately "flush" all pending state updates inside the given callback and synchronously update the DOM.

javascript
import { flushSync } from 'react-dom'; flushSync(() => { setState(newValue); });

After flushSync() returns, React guarantees that:

  • the component has already re-rendered;
  • the DOM is updated;
  • all layout effects (useLayoutEffect) for that update have already run.

1. Why it is needed at all

By default, React works asynchronously, especially in React 18 with Concurrent Rendering. It can:

  • defer updates;
  • combine several setState calls into one render (batching);
  • not update the DOM immediately.

Sometimes this creates situations where you need to see the result in the DOM right away, for example:

  • to measure an element (offsetHeight);
  • to smoothly kick off an animation;
  • to set focus;
  • to react synchronously to a user action.

2. Example: without flushSync

javascript
function Example() { const [count, setCount] = useState(0); const divRef = useRef(); const handleClick = () => { setCount(c => c + 1); console.log(divRef.current.textContent); // old value }; return <div ref={divRef}>{count}</div>; }

What happens:

  • setCount puts the update in the queue;
  • React schedules a render but does not run it instantly;
  • the log runs before the DOM update -> you see the old value.

3. Example with flushSync

javascript
import { flushSync } from 'react-dom'; function Example() { const [count, setCount] = useState(0); const divRef = useRef(); const handleClick = () => { flushSync(() => { setCount(c => c + 1); // state update }); console.log(divRef.current.textContent); // already the new value }; return <div ref={divRef}>{count}</div>; }

Now React:

  1. Immediately runs setCount();
  2. Synchronously runs render and commit;
  3. Updates the DOM;
  4. Only then returns from flushSync;
  5. The log shows the current count.

4. How it works under the hood

flushSync:

  • temporarily disables concurrent batching;
  • forces React to process all pending updates (including ones scheduled earlier);
  • immediately runs the commit phase, updating the DOM and layout effects;
  • then returns React to its normal asynchronous mode.
javascript
Without flushSync: setState() → wait → React decides when to update With flushSync: setState() → render right away → commit → ready DOM

5. Where you need to apply this

ScenarioWhy flushSync is needed
Need to measure the DOM after setStateTo get accurate sizes
Starting an animation right after a changeThe DOM must be updated instantly
Focusing or scrolling after an updateSo the element definitely exists in the DOM
Working with external libraries (GSAP, D3, Chart.js)These libraries expect the current DOM state
Sometimes - when integrating with React Transition Group, Portal, or drag-and-dropWhen the commit needs to happen synchronously

6. But use it carefully!

React deliberately makes rendering asynchronous in order to:

  • avoid blocking the interface,
  • optimize batching of updates,
  • improve UI responsiveness.

flushSync() turns off these benefits for a specific piece of code.

Do not do this:

javascript
flushSync(() => { setA(1); }); flushSync(() => { setB(2); });

Each call forces React to render and commit again, which hurts performance. It is better to group several updates into a single flushSync().


7. Interaction with the lifecycle

StageWhat happens with flushSync()
Render PhaseRuns immediately for all changed components
Commit PhaseHappens synchronously
Effects (useLayoutEffect)Run right after commit
Effects (useEffect)Still run asynchronously (on the next tick)

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.