You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中onScroll事件触发失败,请求分析原因

React页面滚动事件未触发的原因及修复

问题场景

原生JS监听页面滚动可正常给header切换类名:

document.addEventListener("scroll", function(){
const headerChange = document.querySelector("header");
if (window.scrollY > 0) {
headerChange.classList.add("scrolled");
} 
else {
headerChange.classList.remove("scrolled");
} 
})

转成React代码后,页面滚动时事件完全没触发:

const [isScrolling, setIsScrolling] = useState(false);
const navRef = useRef();

const navScroll = () => {
    setIsScrolling(window.scrollY > 0 ? 
    navRef.current.classList.add("scrolled") 
    :  navRef.current.classList.remove("scrolled"));
    console.log(navScroll)
}

return (
<nav
    ref={navRef} 
    onScroll={() => isScrolling}>
</nav>
)

核心问题点

1. 监听对象完全错误

原生代码监听的是**整个页面(document/window)**的滚动,而React代码里把onScroll绑定在了<nav>元素上。只有当<nav>自身有滚动条(比如设置overflow: scroll且内容超出容器)时,它的onScroll才会触发,页面整体滚动不会触发这个元素的滚动事件。

2. 事件绑定逻辑无效

当前onScroll={() => isScrolling}只是引用了状态变量,没有调用处理函数navScroll——就算<nav>能触发滚动,这个写法也不会执行任何逻辑。

3. 状态使用冗余且错误

setIsScrolling接收的是classList.add/remove的返回值(这两个方法返回undefined),完全没必要用状态来处理这个逻辑,属于误用React状态API。


修正后的两种实现方式

方式一:贴近原生逻辑(直接操作DOM)

import { useRef, useEffect } from 'react';

function Nav() {
  const navRef = useRef();

  const handleScroll = () => {
    const isScrolled = window.scrollY > 0;
    if (isScrolled) {
      navRef.current.classList.add("scrolled");
    } else {
      navRef.current.classList.remove("scrolled");
    }
  };

  useEffect(() => {
    // 绑定window滚动事件
    window.addEventListener('scroll', handleScroll);
    // 组件卸载时解绑,避免内存泄漏
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return <nav ref={navRef}></nav>;
}

方式二:React推荐写法(状态控制类名)

import { useState, useEffect } from 'react';

function Nav() {
  const [isScrolled, setIsScrolled] = useState(false);

  useEffect(() => {
    const handleScroll = () => {
      setIsScrolled(window.scrollY > 0);
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  // 用状态动态控制类名,无需操作DOM
  return <nav className={isScrolled ? "scrolled" : ""}></nav>;
}

内容的提问来源于stack exchange,提问作者Mikman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:32:28