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

React中useEffect无法获取更新后state变量值的问题解决

问题根源:闭包陷阱

你遇到的是典型的React闭包陷阱:你的useEffect依赖数组为空,意味着它只会在组件挂载时执行一次。定时器的回调函数捕获的是组件初始渲染时的bboHistory状态(也就是bp为空数组的版本),之后无论bboHistory怎么更新,定时器里访问的始终是这个初始值——这就是为什么你在useEffect里打印bboHistory.bp一直是空数组,每次请求都传0作为index,导致后端返回重复数据。

而setBBOHistory里的prev参数能拿到最新的状态,所以你的图表能正常更新,因为它直接绑定了最新的bboHistory。

修复方案

推荐用useRef来跟踪最新的状态,因为ref的current属性是可变的,不会受闭包限制:

步骤1:添加useRef跟踪最新状态

在组件内声明一个ref,初始值为bboHistory:

const bboHistoryRef = useRef(bboHistory);

步骤2:同步ref与state更新

用useEffect监听bboHistory的变化,每次状态更新时同步更新ref的current值:

useEffect(() => {
  bboHistoryRef.current = bboHistory;
}, [bboHistory]);

步骤3:在定时器里使用ref获取最新状态

修改useEffect里的定时器回调,用bboHistoryRef.current替代直接访问bboHistory:

useEffect(() => {
  const interval = setInterval(() => {
    const currentBP = bboHistoryRef.current.bp;
    console.log("bb_p", currentBP);
    requestBBOHistory(currentBP.length);
  }, 6000);

  return () => clearInterval(interval);
}, []);

完整修改后的代码

import React, {useState, useEffect, useRef} from 'react'
import Plot from 'react-plotly.js'

function PriceHistory() {
  const [bboHistory, setBBOHistory] = useState(
    {
      bt:[], bp:[], ot:[], op:[]
    });
  const bboHistoryRef = useRef(bboHistory);

  // 同步ref与state
  useEffect(() => {
    bboHistoryRef.current = bboHistory;
  }, [bboHistory]);

  async function requestBBOHistory(index) {
    const response = await fetch(`http://127.0.0.1:5000/bbo-history/${index}`);
    const data = await response.json();

    setBBOHistory(prev => {
      console.log("prev",prev)
      console.log("data",data)

      return {
        bt: prev.bt.concat(data.bt),
        bp: prev.bp.concat(data.bp),
        ot: prev.ot.concat(data.ot),
        op: prev.op.concat(data.op),
      };
    });
  }

  useEffect(() => {
    const interval = setInterval(() => {
      const currentBP = bboHistoryRef.current.bp;
      console.log("bb_p", currentBP);
      requestBBOHistory(currentBP.length);
    }, 6000);

    return () => clearInterval(interval)
  }, []);

  return (
    <Plot
      data={[
        {
          x: bboHistory.bt,
          y: bboHistory.bp,
          type: 'scatter'
        },
        {
          x: bboHistory.ot,
          y: bboHistory.op,
          type: 'scatter'
        }
      ]}
    />
  )
}

另一种简化思路(可选)

如果你的请求只需要bp的长度,也可以单独用一个useRef跟踪长度,避免同步整个对象:

const bpLengthRef = useRef(0);

// 同步长度
useEffect(() => {
  bpLengthRef.current = bboHistory.bp.length;
}, [bboHistory.bp.length]);

// 定时器里直接用bpLengthRef.current
requestBBOHistory(bpLengthRef.current);

这样更轻量,适合只需要单个属性的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:33:32