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

React购物车勾选逻辑触发Too many renders无限重渲染报错

购物车勾选功能无限重渲染问题修复

问题根因

触发Too many renders...报错的核心原因如下:

  • 事件绑定错误:复选框的onChange属性直接写了handleCheck(index),属于渲染阶段立即执行函数调用,每次渲染都会触发state更新,state更新又触发重渲染,直接形成死循环
  • 状态冗余错位:勾选状态属于全局购物车数据,在子组件ShoppingItemList里额外存了一份本地checked state,多份状态同步极易出现异常;同时useCallback依赖项设置错误、直接修改浅拷贝后的原对象,都会触发不必要的重渲染
  • 违反状态不可变原则:[...props.shoppingList]是浅拷贝,直接修改updatedList[index].isSelected本质还是修改原状态对象的引用,React无法正确识别状态变更,容易出现渲染异常
  • 逻辑判断无效:App组件中localStorage写入逻辑的判断条件initShoppingItemList !== 0永远成立,会导致无意义的重复写入操作

修复步骤

1. 调整App.js状态逻辑

保持购物车数据为单一数据源,在父组件实现勾选状态切换方法,修复localStorage写入逻辑:

import { React, useState, useEffect, useCallback } from "react";
import ShoppingListForm from "./Components/ShoppingListForm";
import ShoppingItemList from "./Components/ShoppingItemList";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
function App() {
  const initShoppingItemList = JSON.parse(localStorage.getItem("shoppedItem") || "[]");
  const [shoppingItem, setShoppingItem] = useState(initShoppingItemList);

  const addShoppedItemHandler = (shoppedItem) => {
    const id = shoppingItem.length === 0 ? 0 : shoppingItem[shoppingItem.length - 1].id + 1;
    const shoppingListWId = {
      id: id,
      item: shoppedItem.item,
      quantity: shoppedItem.quantity,
      isSelected: shoppedItem.isSelected
    };
    setShoppingItem([...shoppingItem, shoppingListWId])
  };

  // 新增勾选状态切换方法
  const toggleItemSelected = useCallback((itemId) => {
    setShoppingItem(prevList => prevList.map(item => 
      item.id === itemId ? {...item, isSelected: !item.isSelected} : item
    ))
  }, [])

  useEffect(() => {
    localStorage.setItem("shoppedItem", JSON.stringify(shoppingItem));
  },[shoppingItem]);

  return (
    <Router>
      <Routes>
        <Route
          path="/"
          element={<ShoppingListForm onSavedShoppingData={addShoppedItemHandler} />}
        />
        <Route
          exact
          path="/itemList"
          element={<ShoppingItemList shoppingList={shoppingItem} onToggleSelect={toggleItemSelected} />}
        />
      </Routes>
    </Router>
  );
}

export default App;

2. 重写ShoppingItemList.js逻辑

删除子组件冗余的本地state,修正事件绑定方式,将复选框改为受控组件:

import { React } from "react";
import { Link } from "react-router-dom";
import "./ShoppingItemList.css";

const ShoppingItemList = (props) => {
  return (
    <div className="container">
      <div className="title">Shopping List:</div>
      <div className="list-container">
        {props.shoppingList.map((item) => (
          <ul key={item.id}>
            <input 
              type="checkbox" 
              checked={item.isSelected}
              onChange={() => props.onToggleSelect(item.id)} 
            />
            <div className="child">{item.item}</div>
            <div className="child">{item.quantity}</div>
          </ul>
        ))}
      </div>
      <Link to="/">Shopping Form</Link>
      <br></br>
      <div>
        已勾选商品:{props.shoppingList.filter(i => i.isSelected).map(i => i.item).join('、')}
      </div>
    </div>
  );
};
export default ShoppingItemList;

关键修复点说明

  • 事件绑定修正:onChange传入箭头函数包裹调用逻辑,避免渲染阶段直接执行处理函数触发死循环
  • 遵循单一数据源原则:所有购物车状态统一存在父组件App中,子组件只通过props接收数据和触发更新方法,消除多份状态同步问题
  • 严格遵守状态不可变要求:更新选中状态时用map返回全新对象,不直接修改原状态对象引用
  • 复选框改为受控模式:给input绑定checked属性和状态值对应,保证UI展示和业务状态完全同步
  • ShoppingListForm.js原有逻辑无问题,无需修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 23:12:31