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

React中Axios GET请求后useState无法更新数据问题求助

问题分析与修复方案

核心问题

你的代码里有几个关键问题导致状态无法正确更新:

  1. 顶层变量复用污染:formatted和regressionData定义在组件顶层,每次组件渲染或请求时不会重置,会累积之前的数据,导致最终传给setData的是脏数据。
  2. 错误判断逻辑错误:res.data.chart.error != 'null'的判断逻辑不对,API返回的error如果是null(类型是null),和字符串'null'比较永远为true,应该直接判断error是否不存在。
  3. 异步状态更新的误解:setData是异步操作,调用后立刻console.log(data)拿的还是旧值,会误以为状态没更新。

修复后的代码

import React, { useState, useEffect }from 'react'
import ChartBox from './ChartBox'
import {
  Box,
  useMediaQuery,
  Button,
  Typography,
  InputLabel,
  MenuItem,
  FormControl,
  Select
} from '@mui/material'
import FlexBetween from './FlexBetween'
import {
  CartesianGrid,
  Legend,
  Line,
  LineChart,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
  Bar,
  BarChart,
  ScatterChart,
  Scatter,
  Label,
  ComposedChart
} from 'recharts'
import regression, { DataPoint } from 'regression'
import axios from 'axios'

const Regression = () => {
  const [isPredictions, setIsPredictions] = useState(false)
  const [data, setData] = useState([])
  const [stock, setStock] = useState('AAPL')

  const handleChange = (e) => {
    setStock(e.target.value)
    setData([])
  }

  const stocks = ['AAPL', 'MSFT', 'GOOG', 'AMZN', 'NVDA', 'TSLA', 'META', 'XOM', 'WMT', 'JPM', 'KO', 'BAC', 'CSCO', 'MCD', 'PFE', 'NFLX', 'AMD', 'DIS', 'INTC', 'GE']
  const menuItems = stocks.map(stock => <MenuItem key={stock} value={stock}>{stock}</MenuItem>)

  const formatData = (x, high, low) => {
    return { x, high, low }
  }

  const regressionDataFormatted = (i, avg) => {
    return [i, avg]
  }

  const regressionCoordinatesFormatted = (x, y) => {
    return { x, y }
  }

  useEffect(() => {
    // 把变量移到useEffect内部,每次请求重新初始化
    let formatted = []
    let regressionData = []
    let timestamps = []
    let stockData = []

    const options = {
      method: 'GET',
      url: `https://yfapi.net/v8/finance/chart/${stock}`,
      headers: {
        'x-api-key': '<api key>'
      },
      params: {
        range: '6mo',
        region: 'US',
        interval: '1d',
        ticker: stock
      }
    }

    axios.request(options).then((res) => {
      // 修正错误判断:检查是否有result且无error
      const chartResult = res.data.chart.result?.[0]
      if (!res.data.chart.error && chartResult) {
        stockData = chartResult.indicators.quote[0]
        timestamps = chartResult.timestamp

        for (let i=0; i<100; i++) {
          if (!timestamps[i] || !stockData.high[i] || !stockData.low[i]) continue; // 避免undefined数据
          const date = new Date(timestamps[i]*1000)
          const formattedDate = `${date.getMonth()+1}-${date.getDate()}` // 月份+1,避免0-11的问题
          const high = stockData.high[i]
          const low = stockData.low[i]
          const avg = Math.floor((high + low)/2)
          const curr = formatData(formattedDate, high, low)
          const currRegression = regressionDataFormatted(i, avg)

          formatted.push(curr)
          regressionData.push(currRegression)
        }

        const regressionCoefficients = regression.linear(regressionData)

        for (let i=0; i<regressionCoefficients.points.length; i++) {
          const curr = regressionCoordinatesFormatted(regressionCoefficients.points[i][0], regressionCoefficients.points[i][1])
          formatted.push(curr)
        }
        console.log('格式化后的数据:', formatted)
        return formatted;
      }
      return []; // 出错时返回空数组
    })
    .then((formattedData) => {
      setData(formattedData)
      // 不要在这里直接log data,因为setData是异步的,要验证的话可以用useEffect监听data变化
    })
    .catch(err => {
      console.error('请求错误:', err)
    })
  }, [stock])

  // 监听data变化,验证状态是否更新
  useEffect(() => {
    console.log('data状态已更新:', data)
  }, [data])

  return (
    <div style={{width: '100%'}}>
      <FlexBetween
                mb='0.25rem'
                p='1rem 1rem'
            >
                <FlexBetween gap='2rem' color='lightgray'>
                    90-Day Summary
                </FlexBetween>

                <FlexBetween gap='2rem'>
                    <FormControl 
                        variant='standard' 
                        sx={{ 
                            m: 1, 
                            minWidth: 120, 
                            justifyContent: 'space-between'
                        }}
                    >
                        <InputLabel id='demo-simple-select-standard-label'>Stock</InputLabel>
                        <Select
                            labelId='demo-simple-select-standard-label'
                            id='demo-simple-select-standard'
                            value={stock}
                            onChange={handleChange}
                            label='Stock'
                            sx={{ color: 'white', float: 'right', position: 'relative' }}
                        >
                            {menuItems}
                        </Select>
                    </FormControl>
                </FlexBetween>
            </FlexBetween>

            <ResponsiveContainer width='100%' height='100%'>
              <ComposedChart
                width={500}
                height={400}
                data={data}
                margin={{
                  top: 20,
                  right: 80,
                  bottom: 20,
                  left: 20
                }}
              >
                <Tooltip />
                
                <XAxis dataKey='x' type='number' label={{ value: 'Index', position: 'insideBottomRight', offset: 0 }} />
                <YAxis unit='USD' type='number' label={{ value: 'Price', angle: -90, position: 'insideLeft' }} />
                <Scatter name='high' dataKey='high' fill='white' />
                <Scatter name='low' dataKey='low' fill='purple' />
                <Line dataKey='y' stroke='lightgrey' dot={false} activeDot={false} legendType='none' />
              </ComposedChart>
            </ResponsiveContainer>

    </div>
  )
}

export default Regression

关键修复点说明

  1. 变量作用域调整:把formatted、regressionData移到useEffect内部,每次请求时重新初始化,避免数据累积污染。
  2. 修正错误判断:改用检查chart.result是否存在且无error的逻辑,避免因为error类型判断错误导致代码不执行。
  3. 处理异步状态更新:移除setData后的console.log(data),改用单独的useEffect监听data变化来验证状态更新。
  4. 数据安全处理:在循环里加了判空逻辑,避免API返回的部分数据为undefined导致报错;同时修正月份显示(月份是0-11,所以加1)。
  5. 可选优化:useMemo缓存options
    如果想优化性能,可以用useMemo缓存请求配置,避免每次渲染重复创建对象:
const options = useMemo(() => ({
  method: 'GET',
  url: `https://yfapi.net/v8/finance/chart/${stock}`,
  headers: {
    'x-api-key': '<api key>'
  },
  params: {
    range: '6mo',
    region: 'US',
    interval: '1d',
    ticker: stock
  }
}), [stock])

关于useMemo的说明

你提到的useMemo在这里并不是必须的,它的作用是缓存复杂计算的结果,避免每次渲染都重复计算。你的问题根源是变量作用域和异步更新的问题,和useMemo无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:54:56