React项目中NHL球队API重复调用问题及修复咨询
修复冰球统计应用中球队API重复调用的问题
问题根源
- 频繁状态更新触发重渲染:
fetchAllTeamsData循环中每次调用setClub(team)都会触发组件重渲染,而useCallback的依赖数组未包含setClub,导致fetchAllTeamsData的引用在重渲染时可能重新生成,进而触发useEffect再次执行整个数据获取流程。 - React严格模式影响(开发环境):如果开启了严格模式,React会在开发阶段自动重复执行
useEffect和useCallback相关逻辑,加剧重复调用问题。
修复方案
方案1:移除不必要的实时状态更新(推荐)
如果club状态仅用于跟踪处理进度、不需要在UI中实时展示,直接用局部变量替代状态更新,避免频繁触发重渲染:
const fetchAllTeamsData = useCallback(async () => { setLoad(true); const topPlayers = []; for (const team of teamQuery) { // 用局部变量替代setClub,避免触发组件重渲染 const currentClub = team; const teamData = await fetchTeamData(team); if (teamData && teamData.players) { const sortedPlayers = teamData.players.sort((a, b) => b.stats.points - a.stats.points); const teamTopPlayers = sortedPlayers.slice(0, 2); topPlayers.push(...teamTopPlayers); } } // 排序并更新状态 const sortedTopPlayers = topPlayers.sort((a, b) => b.stats.points - a.stats.points); setAllTopPlayers(sortedTopPlayers); const sortedTopGoals = [...topPlayers].sort((a, b) => b.stats.goals - a.stats.goals); setTopGoals(sortedTopGoals); const sortedTopAssists = [...topPlayers].sort((a, b) => b.stats.asists - a.stats.asists); setTopAssists(sortedTopAssists); const sortedMostPIM = [...topPlayers].sort((a, b) => b.stats.penalty - a.stats.penalty); setMostPIM(sortedMostPIM); setLoad(false); }, [teamQuery]);
方案2:保留实时状态更新并修正依赖
如果需要在UI中实时显示当前处理的球队,需将setClub加入useCallback的依赖数组,并添加防重复执行逻辑:
const fetchAllTeamsData = useCallback(async () => { // 防止加载期间重复执行 if (load) return; setLoad(true); const topPlayers = []; for (const team of teamQuery) { setClub(team); const teamData = await fetchTeamData(team); if (teamData && teamData.players) { const sortedPlayers = teamData.players.sort((a, b) => b.stats.points - a.stats.points); const teamTopPlayers = sortedPlayers.slice(0, 2); topPlayers.push(...teamTopPlayers); } } // 排序并更新状态 const sortedTopPlayers = topPlayers.sort((a, b) => b.stats.points - a.stats.points); setAllTopPlayers(sortedTopPlayers); const sortedTopGoals = [...topPlayers].sort((a, b) => b.stats.goals - a.stats.goals); setTopGoals(sortedTopGoals); const sortedTopAssists = [...topPlayers].sort((a, b) => b.stats.asists - a.stats.asists); setTopAssists(sortedTopAssists); const sortedMostPIM = [...topPlayers].sort((a, b) => b.stats.penalty - a.stats.penalty); setMostPIM(sortedMostPIM); setLoad(false); }, [teamQuery, setClub]); // 将setClub加入依赖数组 useEffect(() => { fetchAllTeamsData(); }, [fetchAllTeamsData]);
额外优化:并行请求提升性能
当前串行请求球队数据的效率较低,可以改成并行请求大幅缩短加载时间:
const fetchAllTeamsData = useCallback(async () => { setLoad(true); // 并行发起所有球队数据请求 const teamDataPromises = teamQuery.map(team => fetchTeamData(team)); const allTeamData = await Promise.all(teamDataPromises); const topPlayers = []; allTeamData.forEach(teamData => { if (teamData && teamData.players) { const sortedPlayers = teamData.players.sort((a, b) => b.stats.points - a.stats.points); const teamTopPlayers = sortedPlayers.slice(0, 2); topPlayers.push(...teamTopPlayers); } }); // 排序并更新状态 const sortedTopPlayers = topPlayers.sort((a, b) => b.stats.points - a.stats.points); setAllTopPlayers(sortedTopPlayers); const sortedTopGoals = [...topPlayers].sort((a, b) => b.stats.goals - a.stats.goals); setTopGoals(sortedTopGoals); const sortedTopAssists = [...topPlayers].sort((a, b) => b.stats.asists - a.stats.asists); setTopAssists(sortedTopAssists); const sortedMostPIM = [...topPlayers].sort((a, b) => b.stats.penalty - a.stats.penalty); setMostPIM(sortedMostPIM); setLoad(false); }, [teamQuery]);
内容的提问来源于stack exchange,提问作者Peter Sivak
相关产品推荐
相关产品推荐

