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

为什么fetch返回更新state会渲染全对象数组及坐标反查城市名错位

问题成因
  • fetch属于异步网络请求,响应返回顺序不受代码遍历顺序控制:你按id1、id2、id3的顺序发起请求,很可能id2的请求先拿到结果,你如果按返回顺序往数组里塞值,自然就会出现和workout顺序不匹配的错位问题
  • 城市名存储逻辑错误:原有代码没有把城市名和对应workout的id做绑定,不管是直接覆盖state为单元素数组,还是按返回顺序存到数组里,都无法保证城市名和对应的workout正确匹配
  • 多余的动态key导致强制重绘:外层div绑定了每次渲染都会变化的随机key,每次state更新都会导致整个列表完全销毁重绘,进一步加剧了渲染异常
修复方案

核心思路是将城市名与workout id强绑定,完全不受异步请求返回顺序的影响:

  1. 把存储城市名的state修改为对象结构,以workout id为key存储对应城市名
  2. 请求拿到结果后,直接按对应workout id更新state,不需要考虑返回顺序
  3. 渲染时按当前遍历的workout id读取对应的城市名即可
  4. 增加请求清理逻辑,避免组件卸载后仍更新state导致的内存泄漏
修复后代码
import React, { useEffect, useState } from "react";
import "./styles.css";
import { WorkoutsData } from "./WorkoutLocation";

const App = () => {
  const [workouts, setWorkouts] = useState(WorkoutsData);
  // 用对象存储,key为workout id,value为对应的城市名
  const [cityMap, setCityMap] = useState({});

  useEffect(() => {
    const controllers = [];
    workouts.forEach((workout) => {
      const controller = new AbortController();
      controllers.push(controller);
      fetch(
        `https://geocode.xyz/${workout.coords.latitude},${workout.coords.longitude}?geoit=json`,
        { signal: controller.signal }
      )
        .then((res) => res.json())
        .then((result) => {
          const fullLocation = `${result.staddress || ""}, ${result.city || ""}`.trim();
          // 按id更新,不会出现错位
          setCityMap((prev) => ({
            ...prev,
            [workout.id]: fullLocation
          }));
        })
        .catch((err) => {
          if (err.name !== "AbortError") console.error("位置获取失败:", err);
        });
    });
    // 清理未完成的请求
    return () => controllers.forEach((c) => c.abort());
  }, [workouts]);

  return (
    <div>
      {workouts.map((workout) => (
        <h2 key={workout.id}>
          {cityMap[workout.id] || "加载位置中..."}
        </h2>
      ))}
    </div>
  );
};

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:45:07