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

React中currentRaceIndex更新滞后于handleRaceData调用的问题排查与解决

问题原因分析

你的判断没错,核心问题有两个:

  1. React状态更新的异步性:调用setCurrentRaceIndex后,React不会立刻更新currentRaceIndex的数值,状态更新会被放入队列,等待下一次渲染周期才会生效。
  2. 闭包陷阱:handleRaceData是在组件初始渲染时创建的,它捕获的是当时的currentRaceIndex值(也就是初始的-1)。后续即使currentRaceIndex通过setCurrentRaceIndex更新了,这个函数里的currentRaceIndex还是闭包中保存的旧值——除非组件重新渲染,handleRaceData被重新创建。

再加上你现在是同时发送getRaceData和getQueuePosition请求,服务器返回顺序不确定:如果raceData先返回,此时currentRaceIndex还没更新,自然会用初始值-1进行判断。

解决方案

方案一:调整请求顺序,确保先拿到队列位置再请求比赛数据

直接改变请求逻辑,等服务器返回队列位置后,再请求比赛数据,从根源上避免依赖未更新的状态:

useEffect(() => {
  let isMounted = true;

  const handleRaceQueue = (queue) => {
    console.log("Queue pos from server: " + queue);
    setCurrentRaceIndex(queue);
    // 拿到队列位置后再请求比赛数据
    if (isMounted) {
      socket.emit("getRaceData");
    }
  };

  const handleRaceData = (data) => {
    if (areAllRacesFinished === true && data.length > currentRaceIndex + 1) {
      console.log("data.length:", data.length);
      console.log("currentRaceIndex+1:", currentRaceIndex + 1);
      setAreAllRacesFinished(false);
      socket.emit("updateAreAllRacesFinished", false);
    }
    setRaceData(data);
  };

  const handleAreAllRacesFinished = (data) => {
    console.log("AreAllRacesFinished value from server: " + data);
    setAreAllRacesFinished(data); 
  };

  const handleTimerUpdate = (data) => {
    if (data.raceName === currentRace?.raceName) {
      setTimeRemaining(data.timeRemaining);
    }
  };

  socket.on("queuePosition", handleRaceQueue);
  socket.on("raceData", handleRaceData);
  socket.on("timerUpdate", handleTimerUpdate);
  socket.on("areAllRacesFinished", handleAreAllRacesFinished);

  // 先请求队列位置,不立刻请求比赛数据
  socket.emit("getQueuePosition");

  return () => {
    isMounted = false;
    socket.off("queuePosition", handleRaceQueue);
    socket.off("raceData", handleRaceData);
    socket.off("timerUpdate", handleTimerUpdate);
    socket.off("areAllRacesFinished", handleAreAllRacesFinished);
  };
}, [currentRace?.raceName, areAllRacesFinished]); // 补充依赖,避免闭包陷阱

注意:要把areAllRacesFinished加入useEffect的依赖数组,因为handleRaceData里用到了这个状态,否则依然会出现闭包导致的旧值问题。

方案二:用useRef保存最新的队列索引值

如果无法调整请求顺序(比如服务器返回顺序不可控),可以用useRef来保存currentRaceIndex的最新值——useRef的current属性是可变的,不会受闭包影响:

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

// ...

const currentRaceIndexRef = useRef(-1);
const [currentRaceIndex, setCurrentRaceIndex] = useState(-1);

// 同步state和ref的数值
useEffect(() => {
  currentRaceIndexRef.current = currentRaceIndex;
}, [currentRaceIndex]);

useEffect(() => {
  // Request the latest race data and queue position from the server
  socket.emit("getRaceData");
  socket.emit("getQueuePosition");

  const handleRaceQueue = (queue) => {
    console.log("Queue pos from server: " + queue)
    setCurrentRaceIndex(queue); 
  };

  const handleRaceData = (data) => {
    // 直接用ref里的最新值
    const latestRaceIndex = currentRaceIndexRef.current;
    if (areAllRacesFinished === true && data.length > latestRaceIndex + 1) {
      console.log("data.length:", data.length);
      console.log("currentRaceIndex+1:", latestRaceIndex + 1);
      setAreAllRacesFinished(false);
      socket.emit("updateAreAllRacesFinished", false);
    }

    setRaceData(data);
  };

  // 其他handle函数不变...

  socket.on("queuePosition", handleRaceQueue);
  socket.on("raceData", handleRaceData);
  socket.on("timerUpdate", handleTimerUpdate);
  socket.on("areAllRacesFinished", handleAreAllRacesFinished);

  return () => {
    socket.off("queuePosition", handleRaceQueue);
    socket.off("raceData", handleRaceData);
    socket.off("timerUpdate", handleTimerUpdate);
    socket.off("areAllRacesFinished", handleAreAllRacesFinished);
  };
}, [currentRace?.raceName, areAllRacesFinished]); // 补充依赖

方案三:服务端配合调整数据返回逻辑

如果能控制服务器代码,最彻底的解决方式是:

  • 让服务器在处理getRaceData请求时,确保已经返回过队列位置;
  • 或者把队列位置和比赛数据合并成一个接口返回,这样客户端可以直接用返回的队列值,不需要依赖本地状态更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:39:52