Suggest an editImprove this articleRefine the answer for “Why is useEffect not guaranteed to run right after commit?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`useEffect`** does not run right after commit because it is a passive effect that runs asynchronously, after the browser has finished painting. **Key point:** if you need an effect synchronously right after the DOM update, you use `useLayoutEffect`, not `useEffect`.Shown above the full answer for quick recall.Answer (EN)Image## 1. What the commit phase does In React, every update cycle is split into two big parts: | Phase | What it does | Can it be interrupted? | |---|---|---| | **Render Phase** | React computes what needs to change (a new Virtual DOM) | Yes | | **Commit Phase** | React applies the changes to the real DOM | No | After the **commit phase**, the DOM is already updated, the screen is repainted, and React is ready to call effects (`useEffect`, `useLayoutEffect`, `componentDidMount`, and so on). But, importantly, not all effects have the same priority. --- ## 2. Different types of effects React distinguishes two types of side effects: | Type | Hook | When it runs | |---|---|---| | **Synchronous (layout)** | `useLayoutEffect` | **right after commit**, *before* the screen is painted | | **Passive** | `useEffect` | **asynchronously, after painting and the browser's paint tick** | --- ## 3. Why `useEffect()` is **asynchronous** After commit, React: 1. Updates the DOM. 2. Tells the browser: "ready, the screen can be repainted". 3. **Waits** for the browser to finish painting. 4. Only then calls all the "passive" effects (`useEffect`). This is needed so that: - the UI becomes **visible as fast as possible**; - effects (network requests, timers, subscriptions, and so on) **do not slow down the repaint**; - the browser stays responsive (scroll, input, animation are not blocked). --- ## Example (the difference between `useLayoutEffect` and `useEffect`) ```javascript useLayoutEffect(() => { console.log('useLayoutEffect'); // synchronous, after the DOM update }); useEffect(() => { console.log('useEffect'); // asynchronous, after paint }); ``` Console log: ```javascript render commit useLayoutEffect ← right after commit PAINT (browser) useEffect ← after painting ``` --- ## 4. Why this matters in React 18 and concurrent rendering In React 18, rendering became **interruptible and priority-based** (Concurrent Rendering). Because of this, React can: - delay the `useEffect()` call if there are more urgent tasks (for example, the user clicked something); - **cancel** effects if the render was aborted before commit; - **merge** several renders into one commit and call the effects only once after it. So React *guarantees only one thing*: `useEffect()` will be called **after the DOM has already been updated and the browser has shown the changes**, but **not necessarily instantly** - it could be on the next event loop tick. --- ## 5. What if you need an effect "right after commit"? Then you need to use `useLayoutEffect()`: ```javascript useLayoutEffect(() => { console.log('Synchronously after commit'); }); ``` `useLayoutEffect`: - runs synchronously, right after React updates the DOM; - blocks painting until the callback finishes; - is ideal for measurements (for example, `getBoundingClientRect`). > But using `useLayoutEffect` without a real need is risky, > it can **delay the UI from rendering**. > For most side effects (`fetch`, subscriptions, timers), `useEffect` is preferred. --- ## 6. Visually ```javascript Render phase ↓ Commit phase (DOM updated) ↓ → useLayoutEffect (right away) ↓ Browser painted ↓ → useEffect (asynchronously) ``` --- ## 7. Summary > React **does not call** `useEffect` **right after commit**, > because `useEffect` is a **passive effect** that runs > **asynchronously after the browser has finished painting**. > > This guarantees that: > > - the UI renders as fast as possible, > - effects do not block the interface, > - concurrent rendering stays responsive. --- | Hook | When it runs | Use it for | |---|---|---| | `useLayoutEffect` | right after commit (synchronously) | DOM measurements, layout synchronization | | `useEffect` | after paint (asynchronously) | side effects, requests, subscriptions |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.