如何批量执行Fetch异步请求并解决React链接合并问题
问题:NFL API获取球员姓名后链接合并为一个,无法生成独立链接
我想从NFL API获取橄榄球球员姓名,将每个姓名做成跳转对应球员页面的链接,但当前所有链接被合并成一个,页面输出类似TaaotaTarlaoaortaJoshAllen的内容,而非预期的多个独立加粗链接(如<strong>Tua Tagovailoa</strong> <strong>Patrick Mahomes</strong> <strong>Joe Burrow</strong> <strong>Josh Allen</strong>)。
补充说明:API数据拉取成功,但展示格式不符合需求,需要多个独立链接。未接入API时的测试代码可正常生成多个独立链接,输出如下:
Special Team 1 Special Team 2 Special Team 3 Special Team 4
测试代码:
import { Link } from "react-router-dom" import _navbar from "../NavBar/navbar"; export default function _specialTeamsPage() { const specialteams = [1, 2, 3, 4, 5]; return ( <> <_navbar /> <div> {specialteams.map((specialteam) => ( <Link key={specialteam} to={`/specialteam/${specialteam}`}> Special Team {specialteam} </Link> ))} </div> </> ); }
接入API后出问题的代码:
import { Link } from "react-router-dom"; import _navbar from "../NavBar/navbar"; import React, { useEffect, useState } from "react"; import styles from './card.module.css'; export default function _quarterbacksPage() { const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417]; const [names, setNames] = useState([]); for (let i = 0; i < quarterbacks.length; i++){ const options = { method: 'GET', headers: { 'x-rapidapi-key': 'secret key', 'x-rapidapi-host': 'nfl-api-data.p.rapidapi.com' } }; const FullNameUrl = 'https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=' + quarterbacks[i]; const fetchFullName = async () => { fetch(FullNameUrl, options) .then(response => response.json()) .then(response => { const name = response.athlete.fullName; setNames([...names, ...name]); }) }; useEffect(() => { fetchFullName(); }, []); } return ( <> <div> <_navbar /> {names.map((name) => ( <Link key={name} to={`/quarterback/${name}`}> {name} </Link> ))} </div> </> ); }
问题原因与修复方案
核心问题
- 数组更新逻辑错误:
setNames([...names, ...name])中的...name会把字符串姓名拆分为单个字符(字符串属于可迭代对象),导致names数组存储的是单个字符而非完整姓名,后续渲染时所有字符被拼接在一起。 - 循环内滥用useEffect:在for循环中定义useEffect会导致重复注册副作用,且闭包问题会让每次更新都拿到初始空数组,最终数据混乱。
- Key值不唯一:用姓名作为Link的key,若存在重复姓名会引发React渲染异常。
修复后的代码
import { Link } from "react-router-dom"; import _navbar from "../NavBar/navbar"; import React, { useEffect, useState } from "react"; import styles from './card.module.css'; export default function _quarterbacksPage() { const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417]; const [playerData, setPlayerData] = useState([]); // 批量获取所有球员数据 const fetchAllPlayers = async () => { const options = { method: 'GET', headers: { 'x-rapidapi-key': 'secret key', 'x-rapidapi-host': 'nfl-api-data.p.rapidapi.com' } }; // 并行发起所有API请求 const requests = quarterbacks.map(id => fetch(`https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=${id}`, options) .then(res => res.json()) .then(data => ({ id, name: data.athlete.fullName })) ); const results = await Promise.all(requests); setPlayerData(results); }; useEffect(() => { fetchAllPlayers(); }, []); return ( <> <div> <_navbar /> {playerData.map((player) => ( <Link key={player.id} to={`/quarterback/${player.name}`} style={{ fontWeight: "bold", marginRight: "10px" }} > {player.name} </Link> ))} </div> </> ); }
修复要点
- 正确更新数组:用
[...names, name]替代[...names, ...name],将完整姓名作为数组元素添加,避免拆分字符。 - 统一管理副作用:将所有请求逻辑放入单个useEffect,使用
Promise.all并行处理多请求,提升效率同时避免重复注册。 - 使用唯一Key:以球员ID作为Link的key,保证唯一性,避免渲染异常。
- 添加加粗样式:通过内联样式或CSS类实现姓名加粗效果,符合需求。
内容的提问来源于stack exchange,提问作者Jace Johnson
相关产品推荐
相关产品推荐

