React项目中OpenWeather API温度单位切换参数传递问题
问题分析与解决方案
你的核心问题有两个:
units状态未设置初始值,首次请求时URL中的units参数会是undefined,导致API返回默认单位(开尔文)- 切换单位时没有触发API重新请求,只有点击搜索按钮才会获取数据,所以温度不会自动更新
修改步骤
1. 给units设置默认值
初始化units为一个有效值(比如"metric",对应摄氏度),确保首次请求时参数合法:
const [units, setUnits] = useState("metric");
2. 重构apiCall函数,使其可复用
把原来依赖表单事件的apiCall改成接收城市名和单位作为参数,方便切换单位时调用:
const apiCall = async (cityName, unitType) => { const url = `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${apiKey}&units=${unitType}`; const res = await axios.get(url); setWeather({ descp: res.data.weather[0].description, temp: res.data.main.temp, city: res.data.name, humidity: res.data.main.humidity, wind: res.data.wind.speed, feel: res.data.main.feels_like, }); setCity(res.data.name); };
3. 更新表单提交逻辑
修改表单的onSubmit事件,调用重构后的apiCall并传入输入的城市和当前单位:
<form onSubmit={(e) => { e.preventDefault(); const loc = e.target.elements.loc.value; if (loc.trim()) { // 避免空输入 apiCall(loc, units); } }}>
4. 让单位切换触发API请求
修改SegmentedControl的onChange事件,更新units状态的同时,如果已经搜索过城市(即city有值),就重新调用API获取对应单位的天气数据:
<SegmentedControl value={units} onChange={(newUnits) => { setUnits(newUnits); // 已有城市数据时,重新请求对应单位的天气 if (city) { apiCall(city, newUnits); } }} data={[ { value: "standard", label: ( <Center> <Box>Kelvin</Box> </Center> ), }, { value: "metric", label: ( <Center> <Box>Celsius</Box> </Center> ), }, { value: "imperial", label: ( <Center> <Box>Fahrenheit</Box> </Center> ), }, ]} />
5. 优化天气状态初始值(可选)
把weather的初始状态从空字符串改为null,语义更清晰:
const [weather, setWeather] = useState(null);
修改后的完整关键代码片段
export default function Home() { const [weather, setWeather] = useState(null); const [city, setCity] = useState(""); const [units, setUnits] = useState("metric"); // 设置默认单位 // 重构后的apiCall函数 const apiCall = async (cityName, unitType) => { const url = `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${apiKey}&units=${unitType}`; const res = await axios.get(url); setWeather({ descp: res.data.weather[0].description, temp: res.data.main.temp, city: res.data.name, humidity: res.data.main.humidity, wind: res.data.wind.speed, feel: res.data.main.feels_like, }); setCity(res.data.name); }; const Weath = () => { return ( <div className="container"> <div> <div> <Text mr="xs">Units:</Text> <SegmentedControl value={units} onChange={(newUnits) => { setUnits(newUnits); if (city) { apiCall(city, newUnits); } }} data={[ { value: "standard", label: ( <Center> <Box>Kelvin</Box> </Center> ), }, { value: "metric", label: ( <Center> <Box>Celsius</Box> </Center> ), }, { value: "imperial", label: ( <Center> <Box>Fahrenheit</Box> </Center> ), }, ]} /> </div> </div> {/* 其余渲染代码保持不变 */} </div> ); }; return ( <div className="app"> <div className="search"> <form onSubmit={(e) => { e.preventDefault(); const loc = e.target.elements.loc.value; if (loc.trim()) { apiCall(loc, units); } }}> <input type="text" placeholder="city" name="loc" /> <button className="bttn">Search</button> </form> {weather && <Weath />} </div> </div> ); }
这样修改后,点击单位切换按钮时,只要已经搜索过城市,就会自动重新请求对应单位的天气数据,温度会随之更新。
内容的提问来源于stack exchange,提问作者MaCS
相关产品推荐
相关产品推荐

