React中如何确保获取经纬度后再调用天气API?
解决React中获取地理位置后再请求天气的时序问题
问题根源
你代码里的核心问题是navigator.geolocation.getCurrentPosition是基于回调的异步API,不是Promise,所以await对它无效——代码会直接跳到axios请求那一步,此时lat和long还是初始的0值,自然请求到错误位置的天气。另外,即使你等了,setLat/setLong是异步更新状态的,刚调用完就去读lat/long也拿不到新值。
解决方案
把getCurrentPosition包装成Promise,这样就能用await正确等待位置获取完成,并且直接用回调里的坐标值发起请求,不用依赖状态(避免状态更新的异步延迟)。同时,不要把JSX存在状态里,应该存图标相关的标识,渲染时再生成JSX。
修改后的完整代码
import React from 'react'; import { useState, useEffect } from 'react'; import './css/weather.css' import axios from 'axios'; const Weather = () => { const [temp, setTemp] = useState(0); const [wind, setWind] = useState(''); const [windDir, setWindDir] = useState(''); const [gust, setGust] = useState(''); const [precip, setPrecip] = useState(0); const [iconType, setIconType] = useState(''); // 存day/night const [picName, setPicName] = useState(''); // 存图标文件名 const [city, setCity] = useState(''); const [loading, setLoading] = useState(true); // 加个加载状态更友好 const [error, setError] = useState(''); // 把getCurrentPosition包装成Promise const getCurrentPosition = () => { return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject); }); }; const getWeather = async () => { try { setLoading(true); // 等待位置获取完成 const position = await getCurrentPosition(); const { latitude, longitude } = position.coords; // 直接用获取到的坐标发起请求 const response = await axios.get(`http://api.weatherapi.com/v1/current.json?key=6e6263afb84f44279f731543222510&q=${latitude},${longitude}&aqi=no`); const data = response.data; setCity(data.location.name); setTemp(data.current.temp_f); setWind(data.current.wind_mph); setWindDir(data.current.wind_dir); setGust(data.current.gust_mph); setPrecip(data.current.precip_in); const iconUrl = data.current.condition.icon; setPicName(iconUrl.slice(-7)); setIconType(iconUrl.includes('day') ? 'day' : 'night'); } catch (err) { setError('获取位置或天气失败,请检查权限或网络'); console.error(err); } finally { setLoading(false); } }; useEffect(() => { getWeather(); }, []); if (loading) return <div className='weather-container'>加载中...</div>; if (error) return <div className='weather-container'>{error}</div>; return ( <div className='weather-container'> <p> <img src={`/assets/weather/64x64/${iconType}/${picName}`} alt="天气图标" /> </p> <h2>{city}</h2> <p>{`Current Temp: ${Math.round(temp)} °F`}</p> <p>{`Wind: ${windDir} ${Math.round(wind)} mph Gusts: ${Math.round(gust)} mph`}</p> <p>{`Precip: ${Math.round(precip)}in`}</p> </div> ); }; export default Weather;
关键修改点
- 封装
getCurrentPosition为Promise,让await能正确等待位置获取 - 直接使用回调返回的
latitude和longitude发起请求,跳过状态更新的异步延迟 - 将
icon状态拆分为iconType和picName,不再存JSX,而是在渲染时生成,符合React状态管理最佳实践 - 添加了加载和错误状态,提升用户体验
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

