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

React异步fetch推特数据反转数组返回顺序异常问题

问题根因

顺序错乱由3个代码逻辑问题直接导致:

  • 用forEach遍历执行异步请求时,没有管控请求返回顺序。网络请求耗时存在波动,哪个任务的英雄数据先返回,就会先被写入state数组,和原quests列表的索引完全不对应
  • Array.reverse()是原地修改方法,会直接篡改state中存储的原数组,每次组件重渲染都会触发反转操作,进一步打乱已有顺序
  • useEffect执行时没有重置初始state,若quests引用变化触发effect重跑,会在旧数据基础上重复追加内容,造成数据冗余错位
修复方案

不要依赖请求返回的先后顺序追加数据,直接按照原quests数组的顺序批量处理所有请求,等所有请求按序完成后一次性写入state,从根源上避免顺序错位。

修复后的自定义Hook代码

const twitter = useFetchTwitterMultipleQuests(quests)

export const useFetchTwitterMultipleQuests = (twitterProfileManyQuests) => {
  const [twitter, setTwitter] = useState([])

  useEffect(() => {
    // 每次入参变化先重置状态,避免旧数据残留
    setTwitter([])

    const fetchAllData = async () => {
      // 外层直接映射所有quest的请求,Promise.all返回结果顺序和原quest数组完全一致
      const result = await Promise.all(
        twitterProfileManyQuests.map(async (quest) => {
          // 单个quest下的英雄请求同样用Promise.all包裹,保证英雄顺序和heros数组一致
          const heroList = await Promise.all(
            quest.heros.map(async (hero) => {
              const response = await fetch(
                `${window.location.origin}/.redwood/functions/twitter`,
                {
                  method: 'POST',
                  body: JSON.stringify({ twitter: hero.twitter }),
                }
              )
              const resData = await response.json()
              return resData.data.resultAwaited.data
            })
          )
          return heroList
        })
      )
      // 所有数据按原顺序准备完成后,一次性设置state,不要分多次追加
      setTwitter(result)
    }

    fetchAllData()
  }, [twitterProfileManyQuests])

  // 反转前先浅拷贝数组,避免直接修改原state
  const reversedTwitter = [...twitter].reverse()
  return reversedTwitter
}

更稳妥的长期优化

靠数组索引匹配数据本身容错率极低,建议把返回的twitter数据改成以quest.id为键的对象结构,渲染时直接通过quest id查找对应数据,完全不需要依赖数组顺序:

// hook中调整返回结构为 { [questId]: 对应英雄twitter列表 }
// 渲染时直接通过id取值,彻底避免顺序问题
{quests.map((quest) => (
    <QuestCard key={quest.id}>
        <Link to={routes.quest({ id: quest.id })}>
            <div>
                <h3>{truncate(quest.name)}</h3>
                {quest.heros.map((hero, index) => (
                    <React.Fragment key={hero.id}>
                        {twitter[quest.id]?.[index] && (
                            <span>
                                {hero.name}
                                <p>{twitter[quest.id][index]?.name}</p>
                                <img
                                    src={twitter[quest.id][index]?.profile_image_url}
                                    alt={twitter[quest.id][index]?.name}
                                />
                            </span>
                        )}
                    </React.Fragment>
                ))}
            </div>
        </Link>
        <div className="clear" />
    </QuestCard>
))}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:27:15