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

React TypeScript中useData Hook多JSON对象传递报错排查

解决React中useData Hook返回对象无法使用map遍历的问题

问题描述

修改了CodingWithMosh React入门课程中的useData Hook,用于传递包含多个对象的JSON数据,但使用map遍历时控制台报错“data.map is not a function”,控制台打印显示data是对象而非数组。

接口返回JSON示例

{
  "titles": {
    "recommend": {
      "top": [
        {
          "title_description": "A young Han Solo tries to settle an old score with the help of his new buddy Chewbacca, a crew of space smugglers and a cunning old friend.",
          "title_id": 31536,
          "title_name": "Solo: A Star Wars Story"
        }
      ],
      "new": [
        {
          "title_description": " As the remnants of the Resistance flee Kylo Ren and the First Order, Rey seeks out Luke Skywalker – but he wants nothing more to do with the Force.",
          "title_id": 31571,
          "title_name": "Star Wars: Episode VIII: The Last Jedi"
        }
      ]
    }
  }
}

问题根源

  1. 类型定义不匹配:原FetchResponse接口错误假设返回数据直接包含recommend数组,但实际接口返回的是嵌套结构titles.recommend,且recommend是包含top、new两个数组的对象,并非数组。
  2. 数据提取错误:useData Hook中错误地从res.data.recommend获取数据,实际应该从res.data.titles.recommend提取。
  3. 组件遍历逻辑错误:试图对对象直接使用map方法,而map仅适用于数组。

解决步骤

1. 修正useData Hook的类型与数据提取逻辑

import { useEffect, useState } from "react";
import testapi from "../Services/api-test";
import { AxiosRequestConfig, CanceledError } from "axios";

// 匹配实际返回结构的接口定义
interface FetchResponse<T> {
  titles: {
    recommend: T;
  };
}

const useData = <T>(
  endpoint: string,
  requestConfig?: AxiosRequestConfig,
  deps?: any[]
) => {
  // 调整data类型为对象或null,不再是数组
  const [data, setData] = useState<T | null>(null);
  const [error, setError] = useState("");
  const [isLoading, setLoading] = useState(false);

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

      setLoading(true);
      testapi
        .get<FetchResponse<T>>(endpoint, {
          signal: controller.signal,
          ...requestConfig,
        })
        .then((res) => {
          // 修正数据提取路径
          setData(res.data.titles.recommend);
          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;

2. 修正useTest的类型定义

原Items接口中top、new应为数组类型,而非单个对象:

export interface Items {
  top: Test[];
  new: Test[];
}

export interface Test {
  title_description: string;
  title_id: number;
  title_name: string;
}

const useTest = () => useData<Items>("/titles");

export default useTest;

3. 修正组件遍历逻辑

针对data中的数组进行遍历,而非直接遍历对象:

const { data, error } = useTest();

{error && <div>{error}</div>}
{/* 遍历top数组 */}
{data?.top.map((title) => (
  <ul key={title.title_id} style={{ margin: 0, padding: 0 }}>
    <div className={styles.title} onClick={() => navigate("/title")}>
      {title.title_name}
    </div>
  </ul>
))}

{/* 合并top和new数组后遍历 */}
{data && [...data.top, ...data.new].map((title) => (
  <ul key={title.title_id} style={{ margin: 0, padding: 0 }}>
    <div className={styles.title} onClick={() => navigate("/title")}>
      {title.title_name}
    </div>
  </ul>
))}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 19:05:01