React回调内用useEffect报错,如何实现城市天气数据获取?
解决React中事件回调内调用API的状态更新问题
错误原因
你在onCreate回调里用useEffect触发请求报错,是因为React Hooks必须在组件顶层作用域调用,不能嵌套在事件回调、循环、条件判断这类代码块里,这是React的Hook规则,违反就会触发报错。
正确解法
核心思路是:把用户输入的city存为状态变量,用useEffect监听这个状态的变化,当city更新时自动执行API请求,既符合Hook规则,又能正确处理异步请求的状态更新。
完整代码示例
import { useState, useEffect } from 'react'; import Create from './Create'; function WeatherApp() { // 存储天气数据 const [target, setTarget] = useState(null); // 存储用户输入的城市 const [city, setCity] = useState(''); // 加载状态,优化用户体验 const [loading, setLoading] = useState(false); // 错误状态,捕获请求异常 const [error, setError] = useState(null); // 监听city状态变化,触发API请求 useEffect(() => { // 如果城市为空,直接返回不执行请求 if (!city.trim()) return; const fetchWeatherData = async () => { setLoading(true); setError(null); try { const res = await fetch(`https://goweather.herokuapp.com/weather/${city}`); if (!res.ok) throw new Error('天气数据请求失败'); const weatherData = await res.json(); setTarget(weatherData); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchWeatherData(); }, [city]); // 仅当city变化时,重新执行这个effect // 接收Create组件传来的城市 const handleCitySubmit = (inputCity) => { setCity(inputCity); }; return ( <div> <Create onCreate={handleCitySubmit} /> {/* 根据状态渲染不同内容 */} {loading && <p>正在获取天气数据...</p>} {error && <p>出错了:{error}</p>} {target && ( <div className="weather-info"> <h2>{city}的天气</h2> <p>温度:{target.temperature}</p> <p>天气:{target.description}</p> <p>风力:{target.wind}</p> </div> )} </div> ); } export default WeatherApp;
关键说明
- 状态分离:把用户输入的
city和天气数据target拆成两个独立状态,onCreate回调只负责更新city,逻辑更清晰。 - 合规使用useEffect:在组件顶层定义
useEffect,依赖city状态,当用户输入新城市时,自动触发请求,完全符合Hook规则。 - 异步处理:用
async/await处理fetch请求,同时加入loading和error状态,避免直接读取undefined的target,还能给用户反馈。 - 条件渲染:通过
{target && ...}的方式,确保只有当target有数据时才渲染天气信息,不会出现undefined相关的渲染错误。
内容的提问来源于stack exchange,提问作者user14877200
相关产品推荐
相关产品推荐

