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" } ] } } }
问题根源
- 类型定义不匹配:原
FetchResponse接口错误假设返回数据直接包含recommend数组,但实际接口返回的是嵌套结构titles.recommend,且recommend是包含top、new两个数组的对象,并非数组。 - 数据提取错误:useData Hook中错误地从
res.data.recommend获取数据,实际应该从res.data.titles.recommend提取。 - 组件遍历逻辑错误:试图对对象直接使用
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
相关产品推荐
相关产品推荐

