React报错Too many re-renders,TeamContent组件无限重渲染怎么解决?
问题核心原因
短时间内组件触发了超过React限制的重渲染次数,根源在于代码存在以下可优化点:
- JSX渲染逻辑中直接嵌入了
console.log副作用代码,不符合纯渲染函数规范 - 两个useEffect存在重复的
fetchLiveGames调用逻辑,组件挂载时会连续触发两次直播数据拉取,短时间内多次更新store触发重渲染 - 数组类型的store状态未做浅比较优化,哪怕数据值不变,仅引用变化就会触发重渲染
- 直播数据遍历逻辑冗余,额外增加渲染耗时
修复方案
1. 移除JSX中的副作用代码,重构渲染逻辑
将原本写在三目运算符中的console.log抽离为单独的渲染函数,避免渲染过程中执行额外副作用:
// TeamContent.js 组件内部逻辑 const renderUpcomingGames = () => { if (UpcomingGamesstatus === "error") { console.log("unable to load upcoming games"); return null; } return ( <div className="upcomingGames"> <TeamNext id={props.teamID} /> </div> ); }; const renderPreviousGames = () => { if (previousGamesStatus === "error") { console.log("unable to load previous games"); return null; } return ( <div className="previousGames"> <TeamPrevious /> </div> ); }; // return部分替换为以下代码 return ( <div className="teamDash"> <div className="dashLeft"> <div className="dashLeftHead" style={{ backgroundImage: `url(${props.stadiumImg})`, }} > <div className="dashLeftHeadAbs"></div> <div className="dashLeftHeadIntro"> <span>{props.stadiumName}</span> <h3>{props.teamName}</h3> </div> </div> {liveStatus !== "error" && containsLiveGame && <LiveEvent />} {status !== "error" && ( <div className="dashLeftPlayers"> <TeamPlayers /> </div> )} <div className="dashLeftDesc"> <p>{props.teamDesc}</p> </div> </div> <div className="dashRight"> {renderUpcomingGames()} {renderPreviousGames()} </div> </div> );
2. 合并重复的useEffect逻辑,避免重复拉取数据
删除原本单独写的第二个useEffect,将定时拉取直播数据的逻辑合并到第一个useEffect中,避免组件挂载时重复触发fetchLiveGames:
// 替换原本的两个useEffect为以下代码 useEffect(() => { // 初始拉取所有团队相关数据 dispatch(fetchTeamPlayers(props.teamID)); dispatch(fetchUpcomingGames(props.teamID)); dispatch(fetchPreviousGames(props.teamID)); dispatch(fetchLiveGames()); // 不需要定时拉取可直接删除以下定时器代码 const interval = setInterval(() => { dispatch(fetchLiveGames()); }, 30000); return () => clearInterval(interval); }, [dispatch, props.teamID]);
3. 给useSelector增加浅比较配置,减少不必要重渲染
引入react-redux的shallowEqual,对数组类型的状态做浅比较,只有值真正变化时才触发重渲染:
// 导入shallowEqual import { useDispatch, useSelector, shallowEqual } from "react-redux"; // 修改liveGames的取值逻辑 const liveGames = useSelector((store) => store.userInfo.live.games.all, shallowEqual);
4. 优化直播数据判断逻辑
将遍历全量数据的map改为some,找到第一个符合条件的直播赛事就终止遍历,减少渲染耗时:
const containsLiveGame = liveGames.some((game) => { const verifyHomeTeam = +game.idHomeTeam === +props.teamID; const verifyAwayTeam = +game.idAwayTeam === +props.teamID; return verifyAwayTeam || verifyHomeTeam; });
5. 可选优化:Reducer增加数据不变判断
如果使用Redux Toolkit,可在reducer中增加数据校验,数据未发生变化时不更新state,从根源减少重渲染触发:
// infoSlice.js 中 loadLiveGames reducer 示例 loadLiveGames: (state, action) => { const newLiveGames = action.payload.liveGames; // 浅比较数据是否一致,一致则直接返回不更新 if (JSON.stringify(state.live.games.all) === JSON.stringify(newLiveGames)) { return; } state.live.games.all = newLiveGames; }
如果仅需要页面加载时执行一次初始渲染,不需要后续直播数据更新,直接删除定时器代码即可,后续不会再触发数据拉取和重渲染。
内容的提问来源于stack exchange,提问作者Ivan Telles
相关产品推荐
相关产品推荐

