React中scroll事件触发的动画为什么会有延迟和卡顿?
我用React做页面滚动动画时遇到了问题。当我用window.addEventListener(‘scroll’)监听滚动位置,并用useState更新动画数值时,动画总会有半秒左右的延迟,滑动页面时感觉卡顿。
我试过把更新逻辑放在useEffect里,代码大致是这样的:
useEffect(() => {
const handleScroll = () => {
const scrollTop = window.scrollY;
setScrollPosition(scrollTop); // 更新状态驱动动画
console.log('scroll detected:', scrollTop);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
但实际滚动时控制台输出的信息明显滞后于手指滑动屏幕的动作,动画也跟着延迟。我怀疑是不是setState有性能问题?或者应该用requestAnimationFrame来优化?有没有更好的方案解决这个延迟问题?
你猜对了,得上requestAnimationFrame,还得防抖。但别在useEffect里光绑个scroll就完事,那样每次回调还可能有闭包问题。
直接用这个模式:
关键点三个:
第一,requestAnimationFrame让更新和浏览器刷新率同步,一般是60fps,不会丢帧。
第二,加frameId做节流,避免连续排队多个raf任务。
第三,addEventListener加上{ passive: true },告诉浏览器你不会调用preventDefault,提升滚动响应速度,尤其在移动端特别明显。
如果你动画精度要求不高,甚至可以直接用CSS的transform + will-change来驱动视差,比JS更顺滑。但要是必须用JS读滚动位置,上面这套是最稳的。