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

React组件中socket事件处理器调用的state始终为初始值问题

问题原因与解决方案

问题根源

这是典型的React闭包陷阱:
你的useEffect依赖数组是空的,只会在组件首次挂载时执行一次。此时绑定的socket.on("newNotification")回调,捕获的是组件第一次渲染时生成的showCurrent函数——这个函数里的current是初始值0。

每次点击increment按钮,组件重新渲染时都会生成新的showCurrent函数(里面的current是最新值),但socket的回调还是使用第一次绑定的旧函数,所以触发事件时只会打印0。

而点击show按钮能拿到正确值,是因为按钮的onClick在每次渲染时都会绑定最新的showCurrent函数,调用的自然是包含最新current的版本。

解决方案

方案1:更新useEffect依赖,正确绑定/解绑回调

把showCurrent和socket加入依赖数组,每次依赖变化时先解绑旧回调,再绑定新的:

useEffect(() => {
  // 单独定义回调函数,方便解绑
  const handleNewNotification = () => {
    showCurrent();
  };
  socket.on("newNotification", handleNewNotification);
  
  // 清理函数要解绑对应的回调
  return () => {
    socket.off("newNotification", handleNewNotification);
  };
}, [showCurrent, socket]); // 加入依赖

这样每次showCurrent更新(组件重新渲染后),都会替换socket的回调,保证触发时调用的是最新版本的函数。

方案2:用useRef保存最新的current值

通过useRef同步current的最新值,让showCurrent始终能访问到最新状态:

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

export const DashboardNavbar = (props) => { 
  const socket = useContext(WebsocketContext);
  const [current, setCurrent] = useState(0);
  const currentRef = useRef(current);

  // 同步state到ref,确保ref始终指向最新值
  useEffect(() => {
    currentRef.current = current;
  }, [current]);

  console.log("dashboard is rerendering...")

  const showCurrent = () => {
    // 从ref中取最新值
    console.log("showCurrent is running and current = ", currentRef.current);
  };

  const incrementCurent = () => {
    setCurrent((prev) => prev + 1);
  };

  useEffect(() => {
    socket.on("newNotification", () => {
      showCurrent();
    });
    return () => {
      socket.off("newNotification");
    };
  }, [socket]);

  return (
    <>
      <button onClick={showCurrent}>show</button>
      <button onClick={incrementCurent}>increment</button>
    </>
  );
}  
export default DashboardNavbar;

这个方案不需要修改原useEffect的依赖,适合不想频繁绑定/解绑socket回调的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:43:35