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

React组件中Axios Get请求返回空数组问题排查求助

React PlayingCard组件加载后端数据失败排查

问题描述

PlayingCard组件通过自定义Hook useCards 从后端加载数据,但组件中的data变量始终为空数组。浏览器直接访问接口URL能正常返回JSON,Network面板的payload预览也能看到有效数据,怀疑问题出在前端。

相关代码

PlayingCard组件代码

import {
  Card,
  CardBody,
  CardFooter,
  Flex,
  Image,
  Spacer,
} from "@chakra-ui/react";
import CardIcon from "./CardIcon";
import DescriptionText from "./DescriptionText";
import placeholder from "../images/placeholder.jpg";
import useCards, { GauntletCard } from "../hooks/useCards";

const PlayingCard = () => {
  const { data } = useCards();

  //console.log(data[0]);

  return (
    <Card
      height="350px"
      width="250px"
      backgroundColor="rgba(228, 209, 188, 0.8)"
    >
      <CardBody>
        <Flex>
          <CardIcon />
          <Spacer />
          <CardIcon />
        </Flex>
        <Image padding="10px" fallbackSrc={placeholder}></Image>
      </CardBody>
      <CardFooter>
        <DescriptionText />
      </CardFooter>
    </Card>
  );
};

export default PlayingCard;

Hooks与服务代码

useCards.ts

import useData from "./useData";

export interface GauntletCard {
    id: number;
    title: string;
}

const useCards = () => 
  useData<GauntletCard>('cards/?format=json');

export default useCards;

useData.ts

import { useEffect, useState } from "react";
import { AxiosRequestConfig, CanceledError } from "axios";
import apiClient from "../services/api-client";
  
interface FetchReponse<T> {
    count: number;
    results: T[];
  }

const useData = <T>(endpoint: string, requestConfig?: AxiosRequestConfig, deps?: any[]) => {
    const [data, setData] = useState<T[]>([]);
    const [error, setError] = useState("");
    const [isLoading, setLoading] = useState(false)

    useEffect(() => {
    const controller = new AbortController();

    setLoading(true);

    apiClient
      .get<FetchReponse<T>>(endpoint, {
        signal: controller.signal, ...requestConfig
      })
      .then((res) => {
        setData(res.data.results);
        setLoading(false);
      })
      .catch((err) => {
        if (err instanceof CanceledError) return;
        setError(err.message);
        setLoading(false);
      });
    return () => controller.abort();
  }, deps ? [...deps] : []);

  return { data, error, isLoading };
}

export default useData;

api-client.ts代码

import axios from "axios";

export default axios.create({
    baseURL: 'http://127.0.0.1:8000/', // TEMP: development server
})

疑问解答与排查方案

疑问1:浏览器能正常访问接口是否就可以确定问题出在前端?

不一定100%确定,但结合Network面板能看到有效响应数据的情况,大概率是前端数据处理逻辑存在问题。不过仍需排除以下边缘情况:

  • 前端请求的接口URL与浏览器访问的是否完全一致(比如是否有额外的参数、路径差异)
  • 跨域问题:虽然Network能看到响应,但如果后端未正确配置CORS,可能存在请求被拦截的情况(不过你能看到payload,此概率较低)

疑问2:React StrictMode下两次渲染和请求,第一次报错是否正常?

这是正常现象。StrictMode会在开发环境下触发组件的两次渲染、useEffect的两次执行,第一次执行的useEffect会被cleanup函数(controller.abort())中止请求,所以会出现“Failed to load response data”的报错,第二次请求会正常完成并返回数据。这个现象不会导致data始终为空,因为第二次请求成功后会更新state。

前端排查重点

  1. 检查后端响应结构与FetchReponse接口是否匹配
    在useData.ts的then回调中添加日志,打印res.data,确认后端返回的JSON是否包含results字段:

    .then((res) => {
      console.log('后端响应数据:', res.data);
      setData(res.data.results);
      setLoading(false);
    })
    

    如果后端直接返回数组(而非{count: number, results: T[]}结构),那么res.data.results会是undefined,setData不会改变初始的空数组,这是最可能的原因。此时需要修改useData的逻辑:

    // 如果后端直接返回数组
    .then((res) => {
      setData(res.data);
      setLoading(false);
    })
    
  2. 确认组件是否能接收到更新后的data
    在PlayingCard组件中添加日志,跟踪data的变化:

    const { data, isLoading, error } = useCards();
    console.log('组件当前data:', data);
    console.log('加载状态:', isLoading);
    console.log('错误信息:', error);
    

    如果isLoading变为false后data仍为空,说明后端返回的results本身是空数组,或者setData的逻辑有误。

  3. 检查useEffect的依赖是否正确
    useCards调用useData时未传递依赖数组,useData的useEffect依赖为空数组,这意味着只会在组件挂载时执行一次请求(StrictMode下两次),如果后续需要重新请求,需补充依赖参数,但当前问题与此无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:56:02