0Pricing
React Academy · Lesson

Avoiding Layout Thrash and Visual Flicker

Identify when a useEffect causes visible flicker and replace it with useLayoutEffect to fix it.

Avoiding Layout Thrash and Visual Flicker is a free React Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Layout Thrash

Layout thrash occurs when JavaScript alternates between reading DOM properties and writing to the DOM in a loop. Each read after a write forces the browser to recalculate the layout synchronously to return an accurate value. This can turn what should be a single layout calculation into dozens, severely hurting performance.

How React Batch Updates Help

React batches all setState calls within event handlers and effects into a single re-render. This natural batching prevents the read-write-read pattern that causes thrash within a single render cycle. In React 18, batching extends to async callbacks and Promises as well, reducing layout thrash from concurrent state updates.

When Flicker Happens in useEffect

Flicker occurs when a useEffect reads the DOM, updates state, triggers a re-render, and the browser paints twice: once with the initial state and once with the corrected state. The first paint flashes briefly before being replaced. This is most visible for effects that adjust layout properties like height, width, or position.

Diagnosing Flicker with DevTools

Open Chrome DevTools, go to the Rendering tab (via the three-dot menu under More tools), and enable "Paint flashing." Repaint areas are highlighted in green. If you see a component flash on first render and then immediately re-paint to a different layout, this confirms a double-paint caused by a useEffect-driven state update.

Fixing Flicker by Moving to useLayoutEffect

Move DOM reads and their resulting state updates from useEffect to useLayoutEffect. The same measurement and state update now happen synchronously before paint, React re-renders and commits in the same block, and the browser only paints the final, correct state. The green flashing in DevTools disappears.

The Single-Paint Pattern

The no-flicker pattern is: read DOM in useLayoutEffect, call setState with the measurement, React re-renders synchronously, commits the corrected DOM, and the browser paints once with the final result. This is the standard pattern for tooltip positioning, sticky header offsets, and animation setup.

Valid useEffect Use Cases

The vast majority of effects belong in useEffect: data fetching (the loading flash is acceptable and expected), subscriptions to events or streams, logging and analytics, timers, and any effect that does not immediately affect visible layout. Over-using useLayoutEffect where useEffect would work is an anti-pattern that hurts performance.

Valid useLayoutEffect Use Cases

Reserve useLayoutEffect for DOM measurements that feed back into visual output: tooltip positions, element size-based logic, scroll position restoration, and animation setup that reads initial dimensions. A clear symptom that tells you to switch is seeing a visible one-frame flash of incorrect layout on first render.

Comparing useEffect and useLayoutEffect in Code

The two hooks have identical signatures: useLayoutEffect(callback, deps) vs useEffect(callback, deps). The only difference is the timing of when the callback runs. You can switch between them with a one-word change in the code. Start with useEffect and only change to useLayoutEffect if you confirm flicker.

Combining Both in One Component

It is valid and common to use both hooks in the same component for different concerns. For example, a chart component might use useLayoutEffect to measure its container width and set the SVG viewBox synchronously, and then use useEffect to fetch the chart data asynchronously. Each hook handles the concern where timing matters for it.

Testing for Double Paint

Beyond DevTools paint flashing, you can add a console counter inside your component to count renders. If a component logs "render" twice on first mount — once with the initial state and once with the corrected measurement — you have a double-paint scenario. Moving the measurement to useLayoutEffect should reduce it to one render logged after mount (the double in Strict Mode notwithstanding).

When to Prefer useLayoutEffect over useEffect

Which scenario is the correct reason to use useLayoutEffect instead of useEffect?

Lesson Recap: Layout Thrash and Visual Flicker

Layout thrash comes from alternating DOM reads and writes. React's batching prevents most of it within renders. Flicker happens when useEffect measures the DOM and updates state, causing two paints. Fix flicker by moving DOM measurements to useLayoutEffect. Default to useEffect for everything else: fetching, subscriptions, logging, and timers.

Frequently asked questions

Is the “Avoiding Layout Thrash and Visual Flicker” lesson free?

Yes — the full text of “Avoiding Layout Thrash and Visual Flicker” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.

What will I learn in “Avoiding Layout Thrash and Visual Flicker”?

Identify when a useEffect causes visible flicker and replace it with useLayoutEffect to fix it. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Academy?

No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Avoiding Layout Thrash and Visual Flicker” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Academy lesson?

Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Rendering Phase and DOM Commit
  2. When useLayoutEffect Runs vs useEffect
  3. Measuring DOM Elements with useLayoutEffect
  4. Avoiding Layout Thrash and Visual Flicker
← Back to React Academy