React调用Foreca Weather API获取天气数据的问题排查
问题:Foreca Weather API调用异常排查与优化建议
我尝试通过Foreca Weather API获取天气数据,获取当前天气需要传入对应城市的数字型location参数,这个参数得通过地点搜索接口获取。我写了searchCity函数,先获取location id再传入weatherUrl请求当前天气,但首次搜索时能拿到locations数组却无法获取天气,Axios返回400错误;第二次搜索两者都能获取,但天气数据是上一次请求的结果。附上我的代码:
import React from 'react' import { useState } from 'react'; import axios from 'axios'; const Home = () => { // const [weather, setWeather] = useState({}); const [city, setCity] = useState(''); const [location, setLocation] = useState([""]); const [weather, setWeather] = useState({}); const url = `https://foreca-weather.p.rapidapi.com/location/search/${city}` let weatherUrl; const options = { headers: { 'X-RapidAPI-Key': 'apiKeyHere', 'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com' } }; const weatherOptions = { params: { alt: '0', tempunit: 'C', windunit: 'MS', tz: 'Europe/London', lang: 'en' }, headers: { 'X-RapidAPI-Key': 'apiKeyHere', 'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com' } }; const searchCity = async (e) => { try { if (e.key === 'Enter') { await axios.get(url, options).then((response) => { setLocation(response.data.locations); console.log(response.data); weatherUrl = `https://foreca-weather.p.rapidapi.com/current/${location[0]?.id}`; }) setCity('') // To show the current weather of the city searched currentWeather(); } } catch (err) { console.error(err); } } const currentWeather = async () => { try { await axios.get(weatherUrl, weatherOptions).then((response) => { setWeather(response.data); console.log(response.data); }) } catch (err) { console.error(err); } } return ( <> <div> <div className="search"> <input value={city} onChange={e => setCity(e.target.value)} onKeyPress={searchCity} type="text" /> </div> <div className="weather"> <h1>City:{location[0]?.name}</h1> <h1>Country:{location[0]?.country}</h1> <h1>id:{location[0]?.id}</h1> <h1>weather:{weather.current?.temperature}</h1> </div> </div> </> ) } export default Home;
问题原因分析
- React状态更新的异步性:
setLocation是异步操作,在then回调里调用setLocation后,立刻访问location[0]?.id拿到的还是组件当前的旧状态值。首次搜索时,weatherUrl用了初始空数组的无效id,导致API返回400错误;第二次搜索时,location存储的是上一次的结果,所以请求用了旧id,返回旧数据。 - 变量作用域与时序问题:顶层的
weatherUrl变量会被多次赋值覆盖,再加上异步状态更新的延迟,进一步导致请求地址错误。
优化实现方案
直接绕开异步状态的依赖,用接口返回的原始数据发起天气请求,同时合并逻辑、增加错误处理:
import React, { useState } from 'react'; import axios from 'axios'; const Home = () => { const [city, setCity] = useState(''); const [location, setLocation] = useState([]); const [weather, setWeather] = useState({}); const [errorMsg, setErrorMsg] = useState(''); // 提取重复的请求头,减少冗余代码 const baseHeaders = { 'X-RapidAPI-Key': 'apiKeyHere', 'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com' }; const searchCity = async (e) => { if (e.key !== 'Enter') return; if (!city.trim()) { setErrorMsg('请输入城市名称'); return; } try { setErrorMsg(''); // 1. 先请求城市搜索接口 const locationRes = await axios.get( `https://foreca-weather.p.rapidapi.com/location/search/${city}`, { headers: baseHeaders } ); const locations = locationRes.data.locations; if (!locations || locations.length === 0) { setErrorMsg('未找到匹配的城市'); return; } setLocation(locations); // 2. 直接用接口返回的最新location id请求天气,不用等state更新 const weatherRes = await axios.get( `https://foreca-weather.p.rapidapi.com/current/${locations[0].id}`, { params: { alt: '0', tempunit: 'C', windunit: 'MS', tz: 'Europe/London', lang: 'en' }, headers: baseHeaders } ); setWeather(weatherRes.data); setCity(''); } catch (err) { console.error(err); setErrorMsg('获取数据失败,请稍后重试'); } }; return ( <div> <div className="search"> <input value={city} onChange={e => setCity(e.target.value)} onKeyPress={searchCity} type="text" placeholder="输入城市名称按回车搜索" /> {errorMsg && <p style={{ color: 'red', margin: '8px 0' }}>{errorMsg}</p>} </div> <div className="weather"> {location[0] && ( <> <h1>城市: {location[0].name}</h1> <h1>国家: {location[0].country}</h1> <h1>ID: {location[0].id}</h1> </> )} {weather.current && ( <h1>气温: {weather.current.temperature}°C</h1> )} </div> </div> ); }; export default Home;
优化点说明
- 直接使用接口返回的
locations数据中的id发起天气请求,彻底避免React异步状态更新带来的时序问题 - 合并两个异步请求的逻辑,代码更连贯,减少拆分函数导致的冗余
- 提取重复的请求头配置,降低代码维护成本
- 增加空输入校验、无搜索结果提示、请求失败提示,提升用户体验
- 优化条件渲染,避免无效的空值展示
内容的提问来源于stack exchange,提问作者Jarv1s
相关产品推荐
相关产品推荐

