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

Axios返回数据无法更新React列表问题求助

问题:React中循环Axios请求无法更新列表的解决方案

我需要通过循环发送Axios GET请求,把返回的数据添加到reqs_needed列表中,但列表始终为空——后端能正常返回数据,前端却无法更新列表显示。相关代码如下:

import "./SuggestedClasses.css";
import Axios from "axios";
import { useState, useEffect } from "react";
import TakenClass from "./types";
import {
  Table,
  Thead,
  Tbody,
  Tr,
  Th,
  Td,
  TableContainer,
} from "@chakra-ui/react";

const SuggestedClasses = () => {
  const mapping: Record<number, string> = {
    0: "CI-H",
    1: "CI-M",
    2: "HASS-S",
    3: "HASS-H",
    4: "HASS-A",
  };

  localStorage.setItem("requirements_satisfied", "[2, 2, 1, 1, 1]");
  const requirements_satisfied = JSON.parse(
    localStorage.getItem("requirements_satisfied") as string
  );

  var reqs_filled = JSON.parse(
    localStorage.getItem("requirements_filled") as string
  );

  var reqs_needed: TakenClass[] = [];

  if (localStorage.getItem("requirements_filled") == null) {
    localStorage.setItem("requirements_filled", "[0, 0, 0, 0, 0]");
  }

  for (var i = 0; i < requirements_satisfied.length; i++) {
    if (reqs_filled[i] < requirements_satisfied[i]) {
      var j = 0;
      while (j < requirements_satisfied[i] - reqs_filled[i]) {
        var hass_attribute = null;
        var communication_requirement = null;
        if (mapping[i][0] === "C") {
          hass_attribute = null;
          communication_requirement = mapping[i];
        } else {
          hass_attribute = mapping[i];
          communication_requirement = null;
        }

        useEffect(() => {
          Axios.get("http://localhost:3000/getClass", {
            data: {
              hass_attribute: hass_attribute,
              communication_requirement: communication_requirement,
            },
          }).then((response) => {
            if (response.data) {
              reqs_needed.push(response.data);
            }
          });
        }, []);
        j++;
      }
    }
  }
  console.log("reqs_needed.length", reqs_needed.length);

  return (
    <div className="suggestedClassesContainer">
      <h4 className="card-header">Suggested Classes</h4>
      <TableContainer>
        <Table variant="striped" colorScheme="teal">
          <Thead>
            <Tr>
              <Th>Num.</Th>
              <Th>Rating</Th>
            </Tr>
          </Thead>
          <Tbody>
            {reqs_needed.map((req: TakenClass) => {
              if (req != null) {
                return (
                  <Tr>
                    <Td>{req.subject_id}</Td>
                    <Td>{req.rating}</Td>
                  </Tr>
                );
              }
            })}
          </Tbody>
        </Table>
      </TableContainer>
    </div>
  );
};

export default SuggestedClasses;

错误原因分析

  1. 未使用React状态管理数据:reqs_needed是普通变量,不是useState声明的状态——即使push数据也不会触发组件重渲染,且初始打印时异步请求还未完成,所以长度始终为0。
  2. 违反Hook规则:在for/while循环内调用useEffect,React要求Hook必须在组件顶层调用,不能在循环、条件判断中使用,会导致组件渲染逻辑混乱。
  3. Axios GET请求参数错误:GET请求的参数应该通过params传递,而不是data(data是POST/PUT等请求的参数字段)。
  4. localStorage初始化逻辑漏洞:当requirements_filled不存在时,先设置了localStorage,但后续的reqs_filled还是用了之前的null值解析,会直接报错。

修正后的代码

import "./SuggestedClasses.css";
import Axios from "axios";
import { useState, useEffect } from "react";
import TakenClass from "./types";
import {
  Table,
  Thead,
  Tbody,
  Tr,
  Th,
  Td,
  TableContainer,
} from "@chakra-ui/react";

const SuggestedClasses = () => {
  const mapping: Record<number, string> = {
    0: "CI-H",
    1: "CI-M",
    2: "HASS-S",
    3: "HASS-H",
    4: "HASS-A",
  };

  // 初始化localStorage,避免null问题
  useEffect(() => {
    if (!localStorage.getItem("requirements_satisfied")) {
      localStorage.setItem("requirements_satisfied", "[2, 2, 1, 1, 1]");
    }
    if (!localStorage.getItem("requirements_filled")) {
      localStorage.setItem("requirements_filled", "[0, 0, 0, 0, 0]");
    }
  }, []);

  // 获取localStorage数据,添加默认值防止null报错
  const requirements_satisfied = JSON.parse(
    localStorage.getItem("requirements_satisfied") || "[2, 2, 1, 1, 1]"
  );
  const reqs_filled = JSON.parse(
    localStorage.getItem("requirements_filled") || "[0, 0, 0, 0, 0]"
  );

  // 用useState声明状态变量,存储请求结果
  const [reqsNeeded, setReqsNeeded] = useState<TakenClass[]>([]);

  useEffect(() => {
    // 收集所有需要发送的请求Promise
    const requestPromises: Promise<TakenClass>[] = [];

    for (let i = 0; i < requirements_satisfied.length; i++) {
      const neededCount = requirements_satisfied[i] - reqs_filled[i];
      if (neededCount > 0) {
        const [hassAttribute, communicationRequirement] = mapping[i][0] === "C"
          ? [null, mapping[i]]
          : [mapping[i], null];

        // 添加对应次数的请求到Promise数组
        for (let j = 0; j < neededCount; j++) {
          requestPromises.push(
            Axios.get("http://localhost:3000/getClass", {
              // GET请求用params传递参数
              params: {
                hass_attribute: hassAttribute,
                communication_requirement: communicationRequirement,
              },
            }).then(response => response.data)
          );
        }
      }
    }

    // 批量处理所有请求,完成后统一更新状态
    Promise.all(requestPromises)
      .then(results => {
        setReqsNeeded(results);
      })
      .catch(error => {
        console.error("请求失败:", error);
      });
  }, [requirements_satisfied, reqs_filled]); // 添加依赖项,数据变化时重新请求

  return (
    <div className="suggestedClassesContainer">
      <h4 className="card-header">Suggested Classes</h4>
      <TableContainer>
        <Table variant="striped" colorScheme="teal">
          <Thead>
            <Tr>
              <Th>Num.</Th>
              <Th>Rating</Th>
            </Tr>
          </Thead>
          <Tbody>
            {reqsNeeded.map((req, index) => (
              <Tr key={index}>
                <Td>{req.subject_id}</Td>
                <Td>{req.rating}</Td>
              </Tr>
            ))}
          </Tbody>
        </Table>
      </TableContainer>
    </div>
  );
};

export default SuggestedClasses;

关键修改点

  1. 状态管理:用useState声明reqsNeeded,通过setReqsNeeded更新状态,触发组件重渲染。
  2. Hook规范:所有useEffect都在组件顶层调用,循环收集请求参数后批量处理。
  3. Axios参数修正:GET请求改用params传递参数,符合HTTP规范。
  4. localStorage初始化:单独用useEffect处理初始化,避免渲染时重复设置,同时解析时添加默认值防止null报错。
  5. 批量请求处理:用Promise.all等待所有请求完成后统一更新状态,避免多次触发状态更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:30:35