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

React无按钮调用函数渲染问题:天气应用API调用时机异常

天气应用API调用与组件传参问题

我开发天气应用时遇到两个核心问题:

  • 切换按钮控制天气预报展示时,ThreeDayForecast组件的displayForecast函数不用useEffect就无法触发,用了又会在cityName值准备好前调用API导致报错。
  • 给cityName设置空值默认伦敦的逻辑不生效,但控制台能正确打印cityName。

补充说明:OpenWeather的当前天气接口有准确的高低温、湿度数据,但预报接口数据不准且无湿度,所以采用当前实现方式。


当前代码

ThreeDayForecast组件

const ThreeDayForecast = ( cityName ) => {
    
 // 通过Link传递获取原始输入的cityName

  let api_key = xxx

// 不用useEffect的话displayForecast不会被调用
  const displayForecast = async(cityName) => {
    console.log({ cityName })
    console.log("testing")

    if(cityName ==="") {
       cityName = "London"
    }

    let url = `https://api.openweathermap.org/data/2.5/forecast?q=${cityName}&units=Imperial&appid=${api_key}`

    let response = await fetch(url)
    let data = await response.json()
    // 其他处理代码
  }
  useEffect(() => {
    displayForecast();
  })
  return (
      // 渲染代码
    
  )
}

ForecastButton组件

function toggle() {
  setIsOpen((isOpen) => !isOpen)
}
 
return (
  <div className="container">
    {label}{" "}
    <div className="toggle-switch">
      
      <input type="checkbox" className="checkbox" 
             name={label} id={label} onClick={toggle} />
              
             
      <label className="label" htmlFor={label}>
        <span className="inner" />
        <span className="switch" />
      </label>
      <div style={{ display: isOpen ? 'block' : 'none' }}>
                <ThreeDayForecast  />
               </div>

问题分析

  1. 组件传参格式错误:React组件的props是一个对象,ThreeDayForecast直接写(cityName)会把整个props对象赋值给cityName,而非传入的城市名字符串。
  2. useEffect无依赖且未传参:当前useEffect没有依赖数组,会在组件每次渲染时触发;且调用displayForecast()时未传参,导致函数内部cityName为undefined,空值判断逻辑失效。
  3. 父组件未传递cityName:ForecastButton渲染ThreeDayForecast时没有传入cityName属性,子组件根本无法获取目标城市值。

修复方案

1. 修正ThreeDayForecast组件逻辑

import { useEffect } from 'react';

const ThreeDayForecast = ({ cityName }) => { // 解构props获取正确的cityName
  const api_key = 'xxx'; // 建议用环境变量存储密钥,避免硬编码

  const displayForecast = async(targetCity) => {
    console.log({ targetCity });
    // 处理空值或undefined,默认设为伦敦
    const finalCity = targetCity?.trim() || "London";
    const url = `https://api.openweathermap.org/data/2.5/forecast?q=${finalCity}&units=Imperial&appid=${api_key}`;

    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error('API请求失败');
      const data = await response.json();
      // 数据处理逻辑
    } catch (err) {
      console.error(err);
      // 错误提示逻辑(比如显示错误文案)
    }
  };

  // 依赖数组添加cityName,仅当城市名变化时触发API调用
  useEffect(() => {
    displayForecast(cityName);
  }, [cityName]);

  return (
    // 渲染代码
  );
};

2. 父组件传递cityName

在ForecastButton中渲染子组件时传入cityName(假设父组件已持有该值):

// 假设ForecastButton组件可获取到cityName变量
return (
  <div className="container">
    {label}{" "}
    <div className="toggle-switch">
      <input 
        type="checkbox" 
        className="checkbox" 
        name={label} 
        id={label} 
        onClick={toggle} 
      />
      <label className="label" htmlFor={label}>
        <span className="inner" />
        <span className="switch" />
      </label>
      <div style={{ display: isOpen ? 'block' : 'none' }}>
        {/* 传入cityName给子组件 */}
        <ThreeDayForecast cityName={cityName} />
      </div>
    </div>
  </div>
);

额外优化建议

  • API密钥存入环境变量(比如React项目的.env文件中设置REACT_APP_OPENWEATHER_KEY),调用时用process.env.REACT_APP_OPENWEATHER_KEY,避免代码泄露密钥。
  • 添加加载状态,在API请求过程中显示加载动画,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 11:48:59