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

如何在React的state对象数组中插入新对象实现多城市天气数据渲染

问题原因与修正方案

核心错误点

  • 初始data state定义为数组类型,但两次setData都传入单个对象,直接覆盖了数组结构
  • React state更新要求不可变操作,往数组中追加数据需要基于原数组生成新数组,不能直接修改原数组

优化实现方案

推荐用Promise.all并行发起多个城市的天气请求,一次性更新state,相比链式请求效率更高:

import React, { useEffect, useState } from "react";
import axios from "axios";
import { Container, Card, ListGroup } from "react-bootstrap";

// 记得替换成你自己的openweathermap appkey
const KEY = "你的appid";
// 要查询的城市列表,后续新增城市直接修改这个数组即可
const CITIES = ["Ohio", "California"];

const WeatherPanel = () => {
    const [data, setData] = useState([]);

    const fetchData = async () => {
        try {
            // 并行发起所有城市的天气请求
            const requestList = CITIES.map(city => 
                axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${KEY}`)
            );
            const resList = await Promise.all(requestList);
            // 格式化所有返回结果,生成符合要求的对象数组更新state
            const formattedList = resList.map(res => ({
                description: res.data.weather[0].description,
                icon: res.data.weather[0].icon,
                temp: res.data.main.temp,
                city: res.data.name,
            }));
            setData(formattedList);
        } catch (err) {
            console.log(err);
        }
    };

    useEffect(() => {
        fetchData();
    }, []);

    return (
        <div>
            <Container fluid>
                <Card style={{ width: "50%", boxShadow: "0  0  10px 2px lightgrey" }}>
                    <Card.Header> Favorite Location</Card.Header>
                    <ListGroup variant="flush">
                        {/* 遍历state数组渲染每个城市的天气信息 */}
                        {data.map(item => (
                            <ListGroup.Item key={item.city}>
                                <img src={`http://openweathermap.org/img/wn/${item.icon}@2x.png`} alt={item.description} />
                                {item.city}:{item.temp},{item.description}
                            </ListGroup.Item>
                        ))}
                    </ListGroup>
                </Card>
            </Container>
        </div>
    );
};

export default WeatherPanel;

保留原链式调用写法的修改方案

如果不想调整原有请求逻辑,只需要修改setData的写法即可:

// 第一次请求成功后用函数式更新追加新对象
setData(prev => [...prev, {
    description: res.data.weather[0].description,
    icon: res.data.weather[0].icon,
    temp: res.data.main.temp,
    city: res.data.name,
}]);

// 第二次请求成功后同样用函数式更新,基于上一次的state追加新项
setData(prev => [...prev, {
    description: res.data.weather[0].description,
    icon: res.data.weather[0].icon,
    temp: res.data.main.temp,
    city: res.data.name,
}]);

说明:setData传入函数的参数prev是更新前的最新state,用扩展运算符...prev把原数组的项展开,再追加新对象,就生成了全新的数组完成不可变更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 07:06:02