Why it matters
Timers, intervals or animation state that re-render React with no input keep the main thread busy and drain battery, and every commit competes with the next scroll or tap. The rendered UI is often not even on screen.
How to fix it
Pause the source while it is not visible (IntersectionObserver, document.visibilityState), animate with CSS or WAAPI instead of state, and move ticking values into a ref or a small leaf component.
Example
useEffect(() => {
if (!visible) return;
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, [visible]);References
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-ignoredAnimations keep running with prefers-reduced-motionraf-loop-idlerequestAnimationFrame loop runs while idlescroll-timeline-no-fallbackContent is invisible without scroll-driven-animation supportmultiple-webgl-contextsMultiple WebGL contextsreact-commits-on-scrollReact re-renders while the page scrollsreact-wasted-rendersReact component re-renders with unchanged propsreact-render-stormOne React commit re-renders hundreds of componentsreact-no-namesReact component names are minified