计算距离前等待用户位置信息——异步函数重构方案咨询
如何等待用户位置获取完成后执行距离计算?
我明白你的问题——首页加载时用户位置还没通过地理定位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
相关产品推荐
相关产品推荐

