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

计算距离前等待用户位置信息——异步函数重构方案咨询

如何等待用户位置获取完成后执行距离计算?

我明白你的问题——首页加载时用户位置还没通过地理定位API拿到,直接跑距离计算会得到NaN,核心就是要让地址解析和距离计算的逻辑等用户位置就绪后再触发。咱们可以通过调整依赖和增加前置判断来解决,下面是具体的改造方案:

第一步:先确保用户位置能正确获取并更新状态

首先,你需要一个专门的逻辑来获取用户地理定位(如果localStorage里没有的话),并更新userLat和userLon的状态。把这段代码加到组件里:

useEffect(() => {
  // 先检查本地存储有没有缓存的位置,没有的话调用地理定位API
  const savedLat = localStorage.getItem('userLat');
  const savedLon = localStorage.getItem('userLon');
  
  if (!savedLat || !savedLon) {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        const lat = position.coords.latitude.toString();
        const lon = position.coords.longitude.toString();
        
        // 存到本地存储和状态里
        localStorage.setItem('userLat', lat);
        localStorage.setItem('userLon', lon);
        setUserLat(lat);
        setUserLon(lon);
      },
      (error) => {
        console.error('获取用户位置失败:', error);
        // 这里可以加提示,比如让用户开启定位权限
      }
    );
  } else {
    // 如果本地有缓存,直接更新状态
    setUserLat(savedLat);
    setUserLon(savedLon);
  }
}, []);

第二步:修改原有的距离计算逻辑,添加等待判断

接下来,调整你原来的useEffect,让它只有当userLat和userLon都有有效值时才执行地址解析和距离计算,同时把这两个状态加入依赖数组,这样当位置更新时会自动触发逻辑:

useEffect(() => {
  // 前置判断:确保userLat和userLon是有效的数值
  const validLat = parseFloat(userLat);
  const validLon = parseFloat(userLon);
  if (!userLat || !userLon || isNaN(validLat) || isNaN(validLon)) {
    return; // 位置无效,直接退出
  }

  // 确保data存在再遍历处理
  data?.forEach((el) => {
    Geocode.fromAddress(`${el.street} ${el.houseNumber}, ${el.zip} ${el.city}`)
      .then((res) => {
        const location = res.results[0].geometry.location;
        const dis = getDistance(
          {
            latitude: parseFloat(location.lat),
            longitude: parseFloat(location.lon),
          },
          {
            latitude: validLat,
            longitude: validLon,
          }
        );
        console.log('计算的距离:', dis);
        // 这里可以把距离存到state里,比如给每个活动项添加distance字段
      })
      .catch((err) => console.error('地址解析出错:', err));
  });
}, [data, userLat, userLon]); // 加入userLat和userLon作为依赖,位置更新时重新执行

可选优化:避免重复请求

如果你的data比较大,或者用户位置可能频繁更新(比如测试场景),可以用AbortController来取消未完成的请求,避免资源浪费:

useEffect(() => {
  const validLat = parseFloat(userLat);
  const validLon = parseFloat(userLon);
  if (!userLat || !userLon || isNaN(validLat) || isNaN(validLon)) {
    return;
  }

  const controller = new AbortController();
  const signal = controller.signal;

  data?.forEach((el) => {
    Geocode.fromAddress(`${el.street} ${el.houseNumber}, ${el.zip} ${el.city}`, { signal })
      .then((res) => {
        const location = res.results[0].geometry.location;
        const dis = getDistance(
          { latitude: parseFloat(location.lat), longitude: parseFloat(location.lon) },
          { latitude: validLat, longitude: validLon }
        );
        console.log('计算的距离:', dis);
      })
      .catch((err) => {
        // 忽略取消请求的错误
        if (err.name !== 'AbortError') {
          console.error('地址解析出错:', err);
        }
      });
  });

  // 组件卸载或effect重新触发时,取消所有未完成的请求
  return () => controller.abort();
}, [data, userLat, userLon]);

这样改造后,逻辑就会自动等待用户位置就绪后再执行,不会再出现NaN的问题啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:54:07