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
相关产品推荐
相关产品推荐

