React组件点击按钮局部重渲染问题:解决无限循环报错
解决React组件点击按钮局部重渲染与无限循环问题
问题根源
你遇到的无限重渲染报错,核心原因是在组件渲染阶段直接执行了状态更新函数和业务逻辑:
- 每次组件渲染时,
if(pageNo){setPageArr(emptyArr);}都会调用setPageArr,触发新一轮渲染,形成循环 pageNo===10 ? pageChange(0):null直接调用pageChange,同样会在渲染时触发状态相关操作,加剧循环pageNo用普通变量存储,组件渲染时会被重置,无法正确维护分页状态
修复方案
1. 将分页状态改为React State
把pageNo从普通变量改为useState,让React跟踪其变化并触发必要的重渲染:
const [pageNo, setPageNo] = useState(10);
2. 初始化状态并迁移逻辑到useEffect
组件初始化的逻辑要放到useEffect中,避免每次渲染都执行:
const [loadComponentByPage, setPageArr] = useState([]); // 初始化为空数组,避免初始return useEffect(() => { // 组件初始化或cardData变化时,重新计算初始分页数据 if (cardComponent) { const sortedArray = [...cardComponent].sort((a, b) => b.id - a.id); const initialPageData = sortedArray.slice(0, 10); setPageArr(initialPageData); } }, [cardComponent]); // 依赖cardData,数据变化时重新计算
3. 修改pageChange函数,更新状态而非普通变量
在pageChange中通过setPageNo更新分页状态,同时计算当前页要展示的数据:
function pageChange(num) { if (!cardComponent) return; const sortedArray = [...cardComponent].sort((a, b) => b.id - a.id); const arrayLength = sortedArray.length; const newPageNo = pageNo + num; // 边界判断 if (newPageNo < 10) return; // 最小页码为10,对应第1页 if (newPageNo > arrayLength) return; // 最大页码不超过数据总长度 // 计算当前页要展示的数据 const startIndex = newPageNo - 10; const endIndex = newPageNo; const currentPageData = sortedArray.slice(startIndex, endIndex); // 更新状态,触发组件重渲染 setPageNo(newPageNo); setPageArr(currentPageData); }
4. 移除渲染阶段的状态更新和函数调用
删掉原代码中直接在渲染阶段执行的setPageArr和pageChange(0),避免触发无限循环。
修改后的完整代码
import { useState, useEffect } from 'react'; import { ArrowBackIosSharpIcon, ArrowForwardIosSharpIcon } from '@mui/icons-material'; const LeftCard = ({ cardData: cardComponent, getFileName }) => { const [pageNo, setPageNo] = useState(10); const [loadComponentByPage, setPageArr] = useState([]); useEffect(() => { if (cardComponent) { const sortedArray = [...cardComponent].sort((a, b) => b.id - a.id); const initialPageData = sortedArray.slice(0, 10); setPageArr(initialPageData); } }, [cardComponent]); function pageChange(num) { if (!cardComponent) return; const sortedArray = [...cardComponent].sort((a, b) => b.id - a.id); const arrayLength = sortedArray.length; const newPageNo = pageNo + num; if (newPageNo < 10) return; if (newPageNo > arrayLength) return; const startIndex = newPageNo - 10; const endIndex = newPageNo; const currentPageData = sortedArray.slice(startIndex, endIndex); setPageNo(newPageNo); setPageArr(currentPageData); } return ( <div> {loadComponentByPage .sort((a, b) => a.id - b.id) .reverse() .map((element, i) => ( <div key={element.id}> {/* 用element.id作为key,避免index导致的问题 */} <span className="image-overflow flex "> <img className="left-sec-image ml2 link Dim" src={element.image} alt={element.topicname} /> <div> <h4 className="ml4 mr2 light-purple">{element.topicname}</h4> </div> </span> </div> ))} <div className='ml5'> <button className='ml7' onClick={() => pageChange(-10)}> <ArrowBackIosSharpIcon /> </button> <button className='ml6' onClick={() => pageChange(10)}> <ArrowForwardIosSharpIcon /> </button> </div> </div> ); }; export default LeftCard;
额外优化点
- 用
element.id代替i作为列表项的key,避免列表更新时出现不必要的重渲染或错误 - 复制数组后再排序(
[...cardComponent].sort()),避免修改传入的原始cardComponent数据 - 移除无用的
doNothing()调用,简化按钮点击逻辑
内容的提问来源于stack exchange,提问作者SHERAWAT LOKESH
相关产品推荐
相关产品推荐

