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

React函数组件商品分类筛选出现更新深度超限错误求助

React电商项目分类筛选功能的无限更新循环问题

这是我基于React.js开发的首个电商项目,页面左侧展示商品分类,右侧展示商品列表。我尝试实现按分类筛选商品的功能,已接近完成但遇到了相关错误:

错误提示:

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

我哪里出现了错误?


核心逻辑代码

const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const [categories, setCategories] = useState([]);
const [selectedCategories, setSelectedCategories] = useState([]);


//handling paging
const handlePageChange = (pageNumber) => {
  if (
    pageNumber > 0 &&
    pageNumber <= products.length / 15 &&
    pageNumber !== page
  )
    setPage(pageNumber); 
    
}


const addCategory = (category) => {
  if(!selectedCategories.includes(category)){
      setSelectedCategories(prev => ([...prev, category]))
  }     
}



const removeCategory = (category) => {
  if(selectedCategories.includes(category)){
      const removedList = selectedCategories.filter((item) => (item !== category));
      setSelectedCategories(removedList);
  }
}

const getCategories = () => { 
  fetch('https://dummyjson.com/products/categories')
  .then(res => res.json())  
  .then((data) => {
    setCategories(data);
  })  
  
  .catch((err) => console.log(err));
}

useEffect(() => {
  getCategories() 
  }, [])



const getProducts = () => {
  fetch('https://dummyjson.com/products?limit=90') 
  .then(res => res.json()) 
  .then((data) => {
    if (data.products && data.products.length) setProducts(data.products);
  })  

  .catch((err) => console.log(err));
}



useEffect(() => {
getProducts()
}, [])



useEffect(() => {
  if(selectedCategories.length === 0){
      setProducts(products);

  } else{
    setProducts(products.filter((item)=>(selectedCategories.includes(item.category))));
  }
}, [selectedCategories, products])

JSX代码

分类展示

{categories.map((category) => (
  <div onClick={() => {
    if(selectedCategories.includes(category)){
        removeCategory(category);
    } else{
        addCategory(category);
    }
}}  key={category}> 

      <div className="form-check">
        <input className="form-check-input" type="checkbox" value={category} id={category} />
        <label className="form-check-label" htmlFor={category}>
        {category}     
        </label>
      </div> 
  </div>

))}

商品列表展示

{products.length && (
  <div className='row'>
    {products.slice(page * 15- 15, page * 15).map((item)  => (

      <div className='col-lg-4 mb-4 text-center' key={item.id}>
      <div className='product' key={item.id}> 
      <Link to={`/shop/${item.id}/${item.title.replace(/\s+/g, '-').toLowerCase()}`}>
      <div className='list'>
          <div className='p_photo'>
              <img className='img-fluid' src={item.thumbnail} alt={item.title} /> 
          </div>
          
      </div>
      </Link>

      <div className="Stars" style={{ "--rating": [item.rating] }} />

      <div className='title mt-2'> <Link to={`/shop/${item.id}/${item.title.replace(/\s+/g, '-').toLowerCase()}`}>{item.title}</Link> </div>
            
      <div className='price mt-2'>    
      <span className='sale'>${item.price}</span> 
      <span className='discount'> ({item.discountPercentage}% OFF)</span> 
      </div>
      </div>
      </div>
    
    ))}

  </div>
)}

问题分析与修复方案

问题根源

  1. 无限更新循环:最后一个useEffect的依赖数组包含products,但内部又调用setProducts修改该状态。每次products更新,useEffect就会重新执行,执行后又触发状态更新,形成无限循环。
  2. 丢失原始数据:直接修改products状态进行筛选,会导致原始全量商品数据被覆盖,后续无法恢复到未筛选的状态。

修复步骤

1. 新增状态存储全量商品

把接口返回的完整商品列表单独存储,筛选时基于这个全量数据处理:

const [allProducts, setAllProducts] = useState([]); // 存原始全量商品
const [products, setProducts] = useState([]); // 存筛选后的商品

// 修改getProducts函数
const getProducts = () => {
  fetch('https://dummyjson.com/products?limit=90') 
  .then(res => res.json()) 
  .then((data) => {
    if (data.products && data.products.length) {
      setAllProducts(data.products);
      setProducts(data.products); // 初始化显示全量商品
    }
  })  
  .catch((err) => console.log(err));
}

2. 修正筛选逻辑的useEffect

去掉products依赖,基于allProducts进行筛选,彻底避免循环:

useEffect(() => {
  if(selectedCategories.length === 0){
      setProducts(allProducts); // 无选中分类时恢复全量商品
  } else{
    const filteredProducts = allProducts.filter(item => selectedCategories.includes(item.category));
    setProducts(filteredProducts);
  }
}, [selectedCategories, allProducts])

3. 优化分页逻辑(可选)

把分页计算抽成变量,让代码更清晰:

const maxPage = Math.ceil(products.length / 15);
const handlePageChange = (pageNumber) => {
  if (pageNumber > 0 && pageNumber <= maxPage && pageNumber !== page) {
    setPage(pageNumber); 
  }
}

内容的提问来源于stack exchange,提问作者Firoz Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:27