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

为什么useState钩子在useEffect绑定的滚动回调中无法更新状态?

问题原因
  • 闭包陷阱导致读取的永远是旧状态
    你绑定scroll事件的useEffect依赖数组为空,只会在组件首次挂载时执行一次,绑定的handleScroll函数是首次渲染时创建的,它内部捕获的isFocused永远是初始值false,哪怕后续状态更新,事件回调里拿到的还是旧值,不会同步更新。
  • React状态更新是异步的
    调用setIsFocused(true)后,状态不会在当前执行上下文立刻生效,所以紧接着写的console.log(isFocused)拿到的还是更新前的旧值,并不是状态没有更新成功,只是打印时机不对。
解决方案

方案1:调整事件绑定的依赖项

把isFocused加入useEffect的依赖数组,每次isFocused变化时重新绑定最新的handleScroll函数,同时单独监听状态变化触发打印:

import React, { useEffect, useRef, useState } from "react";

const SectionII = (props) => {
  const sectionRef = useRef();
  const [isFocused, setIsFocused] = useState(false);

  const handleScroll = () => {
    const section = sectionRef.current;
    if (!section) return;
    const { y } = section.getBoundingClientRect(); 

    if(!isFocused && y <= 0) {
      setIsFocused(true);
    }
  };

  // 监听isFocused更新,状态变化后再打印
  useEffect(() => {
    if (isFocused) {
      console.log(true);
    }
  }, [isFocused]);

  // 依赖项加入isFocused,每次状态变化重新绑定最新的回调
  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [isFocused]);

  return (
    <section id="mentorship" ref={sectionRef} style={{borderTop: "1px solid"}}>
      <h1>Section 2</h1>
      <button>Set hash</button>
    </section>
  );
};

export default SectionII;

方案2:用ref存储触发标记(更简洁,性能更好)

如果只需要触发一次打印,不需要用状态存储标记,直接用可变的ref存触发状态即可,不受闭包影响,也不需要重复绑定事件:

import React, { useEffect, useRef } from "react";

const SectionII = (props) => {
  const sectionRef = useRef();
  const hasTriggered = useRef(false); // 用ref存是否已经触发过打印

  const handleScroll = () => {
    const section = sectionRef.current;
    if (!section || hasTriggered.current) return;
    const { y } = section.getBoundingClientRect(); 

    if(y <= 0) {
      hasTriggered.current = true;
      console.log(true);
    }
  };

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

  return (
    <section id="mentorship" ref={sectionRef} style={{borderTop: "1px solid"}}>
      <h1>Section 2</h1>
      <button>Set hash</button>
    </section>
  );
};

export default SectionII;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 18:45:04