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

React使用Async/Await调用天气API时未获取经纬度就发请求报错问题

问题原因分析
  • 你对await的理解存在偏差:await只会暂停后续代码执行,等待它紧跟的Promise对象返回结果,并不会等待前面的非Promise异步逻辑执行完成。navigator.geolocation.getCurrentPosition是回调式异步API,调用后不会阻塞后续代码执行,回调函数会在位置获取成功后才触发,所以第一次执行fetch时,lat和long还是初始的空数组,请求参数非法返回400。
  • useEffect依赖项设置为[lat, long],每次setLat、setLong触发state更新都会重新执行useEffect:第一次位置获取成功后会先触发setLat更新lat值,触发useEffect第二次执行,此时long还是空数组,请求依旧报错;之后setLong触发long更新,useEffect第三次执行,两个参数都有有效值,请求正常返回。
修复方案

核心优化两个点:

  1. 调整lat、long的初始值为null,和空值场景做明确区分
  2. 发请求前增加有效值判断,只有两个参数都不为空时才发起请求

修复后参考代码:

import { useState, useEffect } from 'react';
const Weather = (props) => {
  const [weather, setWeather] = useState({}); // 接口返回对象,初始值用空对象更合理
  const [lat, setLat] = useState(null); // 初始值改为null
  const [long, setLong] = useState(null); // 初始值改为null

  // 只在组件挂载时执行一次位置获取
  useEffect(() => {
    navigator.geolocation.getCurrentPosition(function (position) {
      setLat(position.coords.latitude);
      setLong(position.coords.longitude);
    });
  }, []);

  // 位置更新后再发起请求
  useEffect(() => {
    // 两个参数有一个为空就不发起请求
    if (lat === null || long === null) return;

    const fetchData = async () => {
      const res = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&appid=SomeID&units=imperial&exclude=minutely`);
      const result = await res.json();
      setWeather(result);
    };
    fetchData();
  }, [lat, long]);

  return (
    <React.Fragment>
      <div className={styles.weather}>
        {/* 增加可选链判断,避免weather为空时渲染报错 */}
        <div className={styles.weather__current}>{weather.current?.temp}</div>
        <div className={styles.weather__hourly}>Hourly</div>
        <div className={styles.weather__daily}>5 Day</div>
      </div>
    </React.Fragment>
  );
};

export default Weather;

如果想进一步简化逻辑,也可以把位置获取包装成Promise,合并成一个useEffect实现:

useEffect(() => {
  const fetchData = async () => {
    // 把回调式的位置API包装成Promise
    const position = await new Promise((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(resolve, reject);
    });
    const currentLat = position.coords.latitude;
    const currentLong = position.coords.longitude;
    // 拿到位置后直接发请求
    const res = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${currentLat}&lon=${currentLong}&appid=SomeID&units=imperial&exclude=minutely`);
    const result = await res.json();
    setWeather(result);
    // 后续需要用位置参数的话再存state
    setLat(currentLat);
    setLong(currentLong);
  };
  fetchData();
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:24:02