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

React Native获取API数据时meals对象undefined的TypeError问题

React Native中useFetch Hook无法正确解构TheMealDB API返回的meals对象问题

问题现象

使用自定义useFetch Hook获取TheMealDB API数据时,控制台输出meals为undefined,触发Uncaught TypeError: Cannot read properties of undefined (reading 'strMealThumb')错误;同时存在组件卸载后更新状态的警告。其他页面使用相同Hook可正常运行,当前页面异常。

问题原因

  1. 初始状态不匹配:useFetch中data初始值设为数组[],但TheMealDB的lookup接口返回的是包含meals数组的对象(结构为{ meals: [...] })。组件初始渲染时,解构data.meals会得到undefined,直接访问其属性就会报错。
  2. 路由参数获取错误:直接将route.params(对象)作为id拼接进URL,导致API请求的id无效,返回的meals可能为空或不存在。
  3. Hook依赖缺失:useFetch的useEffect依赖数组为空,当URL(即路由参数id)变化时,不会重新发起请求。
  4. 未处理组件卸载后的请求:请求未完成时组件卸载,调用setData/setLoading会触发状态更新警告。

解决方案

1. 修正useFetch Hook

  • 将data初始值改为对象{},匹配API返回结构
  • 给useEffect添加url依赖,确保URL变化时重新请求
  • 加入axios请求取消逻辑,避免组件卸载后更新状态

修改后的useFetch.js:

import React, { useEffect, useState } from "react";
import axios from "axios";

const useFetch = (url) => {
    const [data, setData] = useState({});
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);

    useEffect(() => {
        const source = axios.CancelToken.source();
        const fetchData = async () => {
            try {
                const response = await axios.get(url, {
                    cancelToken: source.token
                });
                setData(response.data);
                setLoading(false);
            } catch (err) {
                if (!axios.isCancel(err)) {
                    setLoading(false);
                    setError(err.message);
                }
            }
        };
        fetchData();

        return () => {
            source.cancel("组件已卸载,取消请求");
        };
    }, [url]);

    return { data, loading, error };
};
export default useFetch;

2. 修正DetailMeal组件

  • 正确解构路由参数中的id
  • 添加条件渲染,在loading、error或meals不存在时显示对应内容
  • 注意TheMealDB返回的meals是数组,需取第一个元素

修改后的detailMeal.js:

import React from "react";
import { View, Text, ActivityIndicator } from "react-native";

import useFetch from "../../hooks/useFetch/useFetch";
import Style from "./detailMeal.stil";
import DetailCard from "../../components/detailCard/detailCard";

const DetailMeal = ({ route }) => {
    const { id } = route.params;
    const { data: { meals }, loading, error } = useFetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${id}`);

    if (loading) {
        return <View style={Style.container}><ActivityIndicator size="large" /></View>;
    }

    if (error || !meals?.length) {
        return <View style={Style.container}><Text>加载失败或无数据</Text></View>;
    }

    const meal = meals[0];

    return (
        <View style={Style.container}>
            <DetailCard
                imageURL={meal.strMealThumb}
                title={meal.strMeal}
                desc={meal.strInstructions}
            />
        </View>
    );
};
export default DetailMeal;

关键说明

  • 条件渲染是避免undefined属性访问的核心,必须确保meals存在且有数据后,再渲染DetailCard
  • 路由参数的获取需匹配传递方式,若通过navigation.navigate('DetailMeal', { id: 123 })传递,必须解构route.params.id
  • 请求取消逻辑解决了组件卸载后更新状态的警告,提升了应用稳定性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:27:26