# Long tasks blocking the main thread in React

> How to fix long tasks blocking the main thread in React — with the exact fix and copy-paste code.

_Category: Performance · Detector `long-task-attribution` · Severity: warning_

The browser runs your JavaScript on the same single thread it uses to respond to clicks and paint frames, so any task that runs too long freezes everything — the page can’t respond to input while it works. This is what wrecks INP (Interaction to Next Paint) and makes a page feel janky right after load. AI code tends to do expensive work synchronously in render or on mount instead of chunking or deferring it.

## The fix for React

Wrap non-urgent state updates in `startTransition` so React can interrupt them for input, and memoize expensive derived values so they don’t recompute every render. Code-split heavy components with `React.lazy`.

```tsx
import { startTransition, useMemo, lazy } from 'react'

const Heavy = lazy(() => import('./Heavy'))
const rows = useMemo(() => expensiveSort(data), [data])

startTransition(() => setFilter(next)) // keeps typing responsive
```

[React docs](https://react.dev/reference/react/startTransition)

### Steps

1. Profile to find the script behind the long task (VibeCheck names it)
2. Move heavy pure computation into a Web Worker, or chunk it with yielding
3. Defer non-critical work with `requestIdleCallback` / `scheduler.yield`

## How VibeCheck detects it

The `long-task-attribution` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Script causing long frames: bundle.js`
- **Threshold:** A single script attributed to more than 3 long animation frames (LoAF)

## FAQ

### What counts as a long task?

The browser flags any task that occupies the main thread for 50ms or more. VibeCheck goes further and attributes long animation frames back to the specific script responsible, so you know what to fix.

### When should I use a Web Worker vs chunking?

Use a Worker for pure, CPU-bound computation with no DOM access (parsing, crunching, transforming data). Use chunking/yielding when the work must touch the DOM or React state and can be spread across frames.

### How does this relate to INP?

INP measures how long the page takes to visually respond to an interaction. Long tasks are the main cause of poor INP — while a long task runs, the browser can’t process the click or paint the response.

See the general, framework-agnostic fix: https://vibecheck.wcgw.fun/fix/long-tasks.md

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/long-tasks. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
