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

React报错Uncaught Error: Too many re-renders,子组件修改父组件样式失败

问题描述

尝试通过子组件按钮的onMouseEnter/onMouseLeave事件修改父组件样式时,触发React报错:

Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop

即使使用箭头函数绑定事件,仍出现该问题,需实现子组件按钮控制父组件样式的需求。

现有代码示例

App.js

import React, { useState, useEffect } from "react";

import Categories from "./Categories";
import ShopPage from "./components/Products";

export default function App() {
  const [data, setData] = useState(Categories);

  useEffect(() => {
    setData(data);
  }, []);
  
  return (
    <div className="wrapper">
      <ShopPage products={data} filterResult={filterResult} />
    </div>
  );
}

ShopPage 组件

const ShopPage = ({ products }) => {
  return (
    <>
      <div>
        <Products products={products} />
      </div>
    </>
  );
};

Products 父组件

const Products = ({products}) => {
  const [hovered, setHovered] = useState(false);
  const [style, setStyle] = useState(false);
  if (hovered) {
    setStyle({
      // 内联样式
    });
  } else {
    setStyle({
      // 内联样式
    });
  }
  return (
    <>
      <Product setHovered={setHovered} style={style} products={products}/>
    </>
  );
};
export default Products;

Product 子组件

const Product = ({ setHovered, style, products }) => {
  return (
    <div className={styles.items}>
      {products.map((value) => {
        return (
          <>
            <div style={style}>
              <button
                onMouseEnter={() => setHovered(true)}
                onMouseLeave={() => setHovered(false)}
              >
                Add to Cart
              </button>
            </div>
          </>
        );
      })}
    </div>
  );
};

export default Product;
解决方案

错误原因

报错核心是Products组件在渲染阶段直接调用setStyle修改状态:每次组件渲染时,都会执行if-else中的setStyle,触发状态更新后组件会再次渲染,循环往复导致无限渲染。

修复方案

方案1:用useEffect监听状态变化更新样式

将样式更新逻辑放到useEffect中,仅当hovered状态改变时才执行,避免重复触发更新:

const Products = ({products}) => {
  const [hovered, setHovered] = useState(false);
  const [style, setStyle] = useState({});

  // 仅在hovered状态变化时更新样式
  useEffect(() => {
    setStyle(hovered ? {
      // 鼠标悬停时的样式示例
      backgroundColor: "#f5f5f5",
      border: "1px solid #ddd"
    } : {
      // 鼠标离开时的样式示例
      backgroundColor: "transparent",
      border: "1px solid #fff"
    });
  }, [hovered]); // 依赖项设置为hovered

  return (
    <>
      <Product setHovered={setHovered} style={style} products={products}/>
    </>
  );
};
export default Products;

方案2:直接根据状态计算样式(无需额外state)

如果样式不需要持久化存储,可以直接在渲染时根据hovered动态生成样式,减少不必要的状态变量:

const Products = ({products}) => {
  const [hovered, setHovered] = useState(false);

  // 实时根据hovered状态计算样式
  const currentStyle = hovered ? {
    backgroundColor: "#f5f5f5",
    border: "1px solid #ddd"
  } : {
    backgroundColor: "transparent",
    border: "1px solid #fff"
  };

  return (
    <>
      <Product setHovered={setHovered} style={currentStyle} products={products}/>
    </>
  );
};
export default Products;

额外优化

  1. 删除App组件中冗余的useEffect:初始化state已经设置为Categories,无需在useEffect中重复赋值,直接删除以下代码:
useEffect(() => {
  setData(data);
}, []);
  1. 给map循环元素添加唯一key:避免React列表渲染警告,使用产品的唯一标识(如id)作为key:
{products.map((value) => {
  return (
    <div key={value.id}> {/* 替换为产品实际的唯一属性 */}
      <div style={style}>
        <button
          onMouseEnter={() => setHovered(true)}
          onMouseLeave={() => setHovered(false)}
        >
          Add to Cart
        </button>
      </div>
    </div>
  );
})}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:25:24