React中.map()遍历的item返回undefined问题排查求助
问题描述
在<Forecast />组件中遍历对象数组items,map()方法中的item返回undefined。虽然通过console.log能看到数据存在,但渲染item.temp等属性时程序崩溃,提示undefined。
相关代码
Forecast组件
import React from "react" export default function Forecast({ items, title }) { console.log(items) return ( <div> <div className="text-white mx-8 mt-4"> <div className="border-b"> <h1 className="text-xl mb-2">{title}</h1> </div> { items.map((item, i) => { console.log(item) return ( <div key={i} className="flex justify-between my-6"> <div className="flex flex-col items-center"> <span>{item.time}</span> <span> <img src={`https://cdn.weatherbit.io/static/img/icons/${item.icon}.png`} alt="" /> </span> <span>{item.temp}</span> </div> </div> ) }) } </div> </div> ) }
WeatherCard组件
import DefaultCitiesLI from "./DefaultCities" import Inputs from "./Inputs" import TimeAndLocation from "./TimeAndLocation" import TempDetails from "./TempDetails" import Forecast from "./Forecast" import { useEffect, useState } from "react" import { getCurrentData, getDailyData, getHourlyData } from "../api/weatherAPI" export default function WeatherCard() { const [data, setData] = useState({}) const [hourlyData, setHourlyData] = useState({}) const [dailyData, setDailyData] = useState([]) const [inputData, setInputData] = useState([]) useEffect(() => { async function getData() { try { const currentHourlyData = await getHourlyData(inputData) const currentDailyData = await getDailyData(inputData) const currentWeatherData = await getCurrentData(inputData) setData({ current: currentWeatherData }) setHourlyData(currentHourlyData) setDailyData(currentDailyData) } catch (err) { console.error("Error: " + err) return null } } getData() }, [inputData]) console.log(dailyData) return ( <div className="flex justify-center items-center mt-8"> <div className="bg-[#1d2d44] rounded w-[600px] px-12 pt-12"> <ul className="flex justify-center space-x-5"> <DefaultCitiesLI setInputData={setInputData} /> </ul> <Inputs setInputData={setInputData} /> {data.current && <div> <TimeAndLocation weatherData={data.current} /> <TempDetails weatherData={data.current} /> <Forecast items={hourlyData} title="Hourly Forecast" /> <Forecast items={dailyData} title="Daily Forecast" /> </div> } </div> </div> ) }
解决方案
1. 检查接口返回的属性结构
最可能的原因是你假设的属性名(item.temp、item.time、item.icon)与接口实际返回的结构不匹配,比如温度嵌套在main.temp、时间字段是dt_txt、图标在weather[0].icon路径下。
操作步骤:
在Forecast的map函数中打印完整的item对象,确认实际属性路径:
items.map((item, i) => { console.log("完整item结构:", item); // ... 渲染代码 })
根据实际结构修改渲染代码,例如:
<span>{item.main.temp}</span> <span>{item.dt_txt}</span> <img src={`https://cdn.weatherbit.io/static/img/icons/${item.weather[0].icon}.png`} alt="" />
2. 修正hourlyData的初始状态
hourlyData初始状态设为{}(对象),但Forecast需要数组来调用map方法。异步请求未完成时,若data.current已存在,hourlyData还是初始对象,会引发错误。
操作步骤:
将hourlyData的初始状态改为数组:
const [hourlyData, setHourlyData] = useState([])
同时在Forecast中添加空数组兜底渲染:
{items.length > 0 ? ( items.map((item, i) => { // ... 原有渲染代码 }) ) : ( <span className="text-white">加载中...</span> )}
3. 提取接口返回的数组部分
从注释代码推测,接口返回的currentHourlyData可能是包含数组的对象(比如{ data: [...] }),你直接传递整个对象给Forecast,导致items是对象而非数组,遍历出的item是对象键名,无法访问属性。
操作步骤:
确认接口结构后,提取数组部分:
// 方式1:设置状态时提取 setHourlyData(currentHourlyData.data) // 方式2:传递给Forecast时提取 <Forecast items={hourlyData.data} title="Hourly Forecast" />
4. 同步数据加载条件
setState是异步操作,可能出现data.current已更新,但hourlyData/dailyData未完成更新的情况,导致Forecast接收初始状态数据。
操作步骤:
修改条件渲染,同时判断所有依赖数据:
{data.current && hourlyData.length > 0 && dailyData.length > 0 && <div> <TimeAndLocation weatherData={data.current} /> <TempDetails weatherData={data.current} /> <Forecast items={hourlyData} title="Hourly Forecast" /> <Forecast items={dailyData} title="Daily Forecast" /> </div> }
内容的提问来源于stack exchange,提问作者CrveniFlash

