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

Material UI卡片视图渲染触发操作函数引发更新溢出问题排查

问题根源与修复方案

嘿,我一眼就揪出问题所在了!你误用了Material UI Fab组件的属性,这直接引发了无限更新循环。

核心错误:搞错了Fab的事件属性

Material UI的Fab组件并没有action这个点击事件处理属性——你把它和onClick搞混了!更关键的是,Fab的action实际上是一个Ref属性(用于获取组件实例的操作对象)。当你把箭头函数传给action时,React会将其识别为「函数式Ref」,在组件挂载/更新阶段自动调用这个函数。

这就导致你的deleteItem和addItem在组件每次渲染时都会被执行,每次执行又触发setState,组件重新渲染后再次调用函数,形成无限循环,最终抛出了Maximum update depth exceeded错误。

修复步骤

1. 替换action为正确的onClick属性

把所有Fab组件的action换成onClick,这才是Fab的点击事件处理函数:

// 删除项的Fab
<Fab onClick={() => deleteItem(entry.key)}>
  <DeleteIcon />
</Fab>

// 添加项的Fab
<Fab onClick={() => addItem()}>
  <AddIcon />
</Fab>

2. 给列表项添加唯一key(最佳实践)

你在gridItemMap.map返回的外层Grid组件上没有设置key,这会触发React的渲染警告,也可能导致潜在的渲染混乱。给它加上和子项一致的唯一key:

{gridItemMap.map( (entry) => (
  <Grid key={entry.key} container direction="row" spacing={1} >
    <GridItem {...entry.props}></GridItem>
    <Fab onClick={() => deleteItem(entry.key)}>
      <DeleteIcon />
    </Fab>
  </Grid>
))}

3. 使用函数式更新修改状态(避免闭包问题)

当你的新状态依赖于当前状态时,应该使用setState的函数形式,这样能确保每次更新都基于最新的状态,避免闭包捕获旧状态导致的错误(比如连续点击添加按钮时,只会添加一个项的问题):

function deleteItem(key: string) : void {
  console.log("deleting " + key);
  setGridItemMap(prevMap => prevMap.filter(value => value.key !== key));
}

function addItem() : void {
  // 生成唯一key,避免重复
  const newKey = `key${Date.now()}`;
  setGridItemMap(prevMap => prevMap.concat({key : newKey, props: props1}));
}

修改后的完整代码

const App: React.FC = () => {
  function deleteItem(key: string) : void {
    console.log("deleting " + key);
    setGridItemMap(prevMap => prevMap.filter(value => value.key !== key));
  }
  function addItem() : void {
    const newKey = `key${Date.now()}`;
    setGridItemMap(prevMap => prevMap.concat({key : newKey, props: props1}));
  }
  const props1 : GridItemProps = {title:"TitleProp1", body:"BodyProp1"};
  const [gridItemMap, setGridItemMap] = useState([
    {key: "key1", props: props1},
  ]);
  return (
    <Container maxWidth="sm">
      <Grid container direction="column" justify="space-evenly" alignItems="stretch" spacing={1} >
        {gridItemMap.map( (entry) => (
          <Grid key={entry.key} container direction="row" spacing={1} >
            <GridItem {...entry.props}></GridItem>
            <Fab onClick={() => deleteItem(entry.key)}>
              <DeleteIcon />
            </Fab>
          </Grid>
        ))}
        <Fab onClick={() => addItem()}>
          <AddIcon />
        </Fab>
      </Grid>
    </Container>
  );
}

这些修改后,你的组件就能正常工作,不会再出现无限循环的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:26:09