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

React Hooks 滚动事件回调中修改state不生效问题如何解决

问题根源

你的问题本质是React函数组件的闭包陷阱:

  • 首次组件渲染时,handle函数会捕获当前作用域下的初始myState值false
  • 你绑定滚动事件的useEffect依赖只有props.run,只要props.run不变,就只会在首次符合条件时绑定一次初始的handle函数
  • 后续myState更新触发组件重渲染,生成的新handle函数会捕获最新的myState值,但你没有更新绑定的事件回调,元素上绑定的永远是最初那个闭包了旧myState的handle,所以每次判断!myState都为真,就会一直打印Set
  • 另外你单独写的空依赖卸载useEffect也存在逻辑问题,它捕获的handle也是初始版本,卸载时可能无法正确移除事件。

修复方案

方案1:补全useEffect依赖,动态更新事件绑定

把事件绑定和卸载逻辑合并到同一个useEffect里,把handle加入依赖数组,这样每次handle变化时都会先移除旧事件,再绑定新事件,就能拿到最新的状态:

const [myState, setMyState] = useState(false);
const refA = useRef(null)
// 用useCallback缓存handle,避免不必要的事件重绑定
const handle = useCallback((e) => {
    if (!myState) {
        console.log('Set', myState)
        setMyState(true);
    }else {
        console.log('no set')
    }
}, [myState])

useEffect(() => {
    if (!props.run || !refA.current) return;
    const ref = refA.current;
    ref.addEventListener("scroll", handle, { passive: true });
    // 卸载逻辑直接写在同一个effect的返回里,自动清理旧事件
    return () => {
        ref.removeEventListener("scroll", handle, { passive: true });
    }
}, [props.run, handle]); // 把handle加入依赖数组

方案2:用ref存储最新状态,避免频繁操作事件监听

如果不想频繁解绑/绑定事件,可以用一个ref同步myState的最新值,handle里直接读ref的current值,就不会受闭包影响:

const [myState, setMyState] = useState(false);
const myStateRef = useRef(myState);
// 同步状态到ref
useEffect(() => {
  myStateRef.current = myState;
}, [myState]);

const refA = useRef(null)
const handle = (e) => {
    if (!myStateRef.current) { // 读取ref而不是直接读state
        console.log('Set', myStateRef.current)
        setMyState(true);
    }else {
        console.log('no set')
    }
}
useEffect(() => {
    if (!props.run || !refA.current) return;
    const ref = refA.current;
    ref.addEventListener("scroll", handle, { passive: true });
    return () => {
        ref.removeEventListener("scroll", handle, { passive: true });
    }
}, [props.run]); // 不需要加handle依赖,handle不会捕获旧状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:09:01