如何修复React分页功能中useEffect的无限循环问题
分页功能无限循环问题分析与修复
问题原因
- 无限循环触发逻辑:你把
products加入了useEffect的依赖数组,同时在useEffect内部调用setProducts修改该状态。每次setProducts执行后,products状态更新,会再次触发useEffect运行,进而再次执行setProducts,形成无限循环。 - 原始数据丢失问题:你用切片后的分页数据覆盖了原始的
products状态,导致切换页码时,原始产品数据已丢失,无法正确切出其他页的内容。
修复方案
核心思路是拆分状态职责,把原始产品数据和当前分页展示的数据分开处理:
- 原始静态数据直接使用导入的
data.products,无需存入状态(因为它不会变化)。 - 新增
displayProducts状态专门存储当前页要展示的切片数据。 - 调整
useEffect的依赖,只监听currentPage的变化,避免触发不必要的重执行。
修复后完整代码
import React, { useState, useEffect } from "react"; import data from './products.json' import Product from "./components/Product/Product"; const PRODUCTS_PER_PAGE = 12 export const Shop = () => { const [currentPage, setCurrentPage] = useState(1) const [displayProducts, setDisplayProducts] = useState([]) // 用原始数据计算总页数,避免依赖变化的状态 const totalPages = Math.ceil(data.products.length / PRODUCTS_PER_PAGE) useEffect(() => { const firstIndex = (currentPage - 1) * PRODUCTS_PER_PAGE const lastIndex = firstIndex + PRODUCTS_PER_PAGE // 从原始数据中切片,保留完整数据源 const slicedProducts = data.products.slice(firstIndex, lastIndex) setDisplayProducts(slicedProducts) }, [currentPage]) // 仅依赖currentPage,彻底避免循环 return ( <div className="products"> {displayProducts.map((product) => ( <Product key={product.id} product={product} /> // 必加key属性,符合React最佳实践 ))} {/* 可选:添加分页控制按钮 */} <button onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} > 上一页 </button> <span>第 {currentPage} 页 / 共 {totalPages} 页</span> <button onClick={() => setCurrentPage(prev => Math.min(prev + 1, totalPages))} disabled={currentPage === totalPages} > 下一页 </button> </div> ) }
补充说明
- 你之前考虑移除
products依赖的方向是对的,但单纯移除依赖无法解决原始数据丢失的问题,必须拆分状态才能实现正常分页。 - 列表渲染时添加
key属性是React的强制要求,能避免组件重渲染异常和控制台警告。
内容的提问来源于stack exchange,提问作者Andrew Ivanov
相关产品推荐
相关产品推荐

