You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:01:35