---
title: "React re-renders while the page scrolls (smooth/react-commits-on-scroll)"
description: "smooth/react-commits-on-scroll: Scroll position, scroll-spy or in-view state held in React turns every scroll event into a render and commit on the main…"
canonical: https://void.parthkapoor.me/rules/smooth/react-commits-on-scroll
lastModified: 2026-09-16
---

# React re-renders while the page scrolls

`smooth/react-commits-on-scroll` · severity **warn** · category Smoothness · detected by `void smooth` and `void audit`

## Why it matters

Scroll position, scroll-spy or in-view state held in React turns every scroll event into a render and commit on the main thread, the same thread that must produce each scroll frame. It costs little on a fast laptop and drops frames on a phone.

## How to fix it

Keep scroll position out of React state: drive the effect with CSS scroll-driven animations or IntersectionObserver, write to a ref and update the DOM in requestAnimationFrame, or subscribe with useSyncExternalStore and only emit when a threshold is crossed.

## Example

```
// before: const [y, setY] = useState(0); onScroll = () => setY(scrollY)
// after: only re-render when the header state actually flips
const scrolled = useSyncExternalStore(subscribeScroll, () => scrollY > 80);
```

## References

- https://react.dev/reference/react/useSyncExternalStore
- https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline

## More smoothness rules

`void smooth` reports 18 rules in this category. How the page feels after it loads: dropped frames during a scripted scroll, long animation frames, INP of real clicks, shifts after input, animated layout properties, idle rAF loops and reduced-motion handling.

- `reduced-motion-ignored` Animations keep running with prefers-reduced-motion — [smooth/reduced-motion-ignored](https://void.parthkapoor.me/rules/smooth/reduced-motion-ignored)
- `raf-loop-idle` requestAnimationFrame loop runs while idle — [smooth/raf-loop-idle](https://void.parthkapoor.me/rules/smooth/raf-loop-idle)
- `scroll-timeline-no-fallback` Content is invisible without scroll-driven-animation support — [smooth/scroll-timeline-no-fallback](https://void.parthkapoor.me/rules/smooth/scroll-timeline-no-fallback)
- `multiple-webgl-contexts` Multiple WebGL contexts — [smooth/multiple-webgl-contexts](https://void.parthkapoor.me/rules/smooth/multiple-webgl-contexts)
- `react-wasted-renders` React component re-renders with unchanged props — [smooth/react-wasted-renders](https://void.parthkapoor.me/rules/smooth/react-wasted-renders)
- `react-render-storm` One React commit re-renders hundreds of components — [smooth/react-render-storm](https://void.parthkapoor.me/rules/smooth/react-render-storm)
- `react-idle-commits` React keeps committing while the page is idle — [smooth/react-idle-commits](https://void.parthkapoor.me/rules/smooth/react-idle-commits)
- `react-no-names` React component names are minified — [smooth/react-no-names](https://void.parthkapoor.me/rules/smooth/react-no-names)

Detected by `void smooth` and `void audit`. Explain it in a terminal: `void rules smooth/react-commits-on-scroll`
