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

Socket.io接收消息时useState状态未即时更新问题求助

问题原因

你碰到的是React的闭包陷阱:Socket.io的回调函数在组件首次渲染时就被绑定了,它捕获的是当时totalScore的初始值(0)。之后不管totalScore状态怎么更新,这个回调里的totalScore始终是闭包中保存的初始值,导致第二次触发时计算逻辑出错,看起来像是totalScore变回了0。

解决方案

下面提供三种可行的解决方式,你可以根据场景选择:

方案1:使用函数式更新获取最新状态

利用setState的函数式形式,直接获取前一次的最新状态,避免闭包带来的旧值问题:

socket.on(`${WsTopic.GAME}/${WsAction.STOP}`, (payload) => {
  const user = payload.find((entry: any) => entry.username == name)
  if (user) {
    console.log("USER: ", user," USER.SCORE: ", user.score);
    
    // 通过函数式更新拿到最新的prevTotalScore
    setTotalScore(prevTotalScore => {
      const addedScore = user.score - prevTotalScore;
      setAddedScore(addedScore);
      setShowAnswer(true);
      return user.score;
    });
  }
})

方案2:用useRef同步最新状态

用useRef保存totalScore的最新值,确保回调能随时获取到当前的状态:
首先声明ref并同步状态:

import { useState, useRef, useEffect } from 'react';

// ...
const totalScoreRef = useRef<number>(0);
const [totalScore, setTotalScore] = useState<number>(0);

// 每次totalScore更新时同步到ref
useEffect(() => {
  totalScoreRef.current = totalScore;
}, [totalScore]);

然后修改回调逻辑:

socket.on(`${WsTopic.GAME}/${WsAction.STOP}`, (payload) => {
  const user = payload.find((entry: any) => entry.username == name)
  if (user) {
    console.log("USER: ", user," USER.SCORE: ", user.score);
    console.log("SCORE: ", totalScoreRef.current);

    const addedScore = user.score - totalScoreRef.current;

    setTotalScore(user.score);
    setAddedScore(addedScore);
    setShowAnswer(true);
  }
})

方案3:用useCallback+useEffect重新绑定事件

如果组件中name等依赖项可能变化,用这种方式确保回调始终拿到最新的状态和依赖:

import { useState, useCallback, useEffect } from 'react';

// ...
const [totalScore, setTotalScore] = useState<number>(0);
const [addedScore, setAddedScore] = useState<number>(0);
const [showAnswer, setShowAnswer] = useState<boolean>(false);

const handleStopMessage = useCallback((payload) => {
  const user = payload.find((entry: any) => entry.username == name)
  if (user) {
    console.log("USER: ", user," USER.SCORE: ", user.score);
    console.log("SCORE: ", totalScore);

    const addedScore = user.score - totalScore;

    setTotalScore(user.score);
    setAddedScore(addedScore);
    setShowAnswer(true);
  }
}, [name, totalScore]); // 添加所有依赖项

// 组件挂载/依赖变化时绑定事件,卸载时解绑
useEffect(() => {
  const eventName = `${WsTopic.GAME}/${WsAction.STOP}`;
  socket.on(eventName, handleStopMessage);
  
  return () => {
    socket.off(eventName, handleStopMessage);
  };
}, [handleStopMessage]);

内容的提问来源于stack exchange,提问作者Bog the Coder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 22:26:27