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

React表单点击按钮组提交事件失效及按钮类型切换需求

问题描述

为表格过滤功能制作了一个按钮组,仅用于切换激活按钮的样式,因此把表格和按钮组包裹在form标签中(表格过滤可能用到多个按钮组)。但点击轮廓样式按钮时,onSubmit事件无法触发,只有在按钮组的onClick中修改状态时才会出现这个问题。

问题更新排查

经排查,当使用getUniqueId()(基于uuid v4生成ID)作为key,或在点击处理函数中修改按钮类型(即使是原生按钮)时会出现该问题。点击处理函数的执行早于提交事件。现在的需求是:点击同一按钮时,将其类型从submit改为button以避免重复触发提交事件,同时不丢失正常的提交事件。

相关代码

ButtonGroup组件

interface ButtonGroupProps {
  labels: string[];
}

const ButtonGroup: FC<ButtonGroupProps> = ({ labels }) => {
  const [active, setActive] = useState<number>(0);

  const handleClick = (index: number) => () => {
    setActive(index);
  }

  return (
    <GroupWrapper>
      {labels.map((label, index) => {
        const props: ButtonProps = active === index ? ({
          variant: 'contained',
          type: 'button',
        }) : ({
          variant: 'outlined',
          type: 'submit',
          onClick: handleClick(index),
        })

        return (
          <Button
            key={getUniqueId()} 
            text={label} 
            borderRadius='16px' 
            padding='2px 12px' 
            borderWidth='2px'
            {...props}
          />
        )})}
    </GroupWrapper>
  )
}

export default ButtonGroup

包含表格的表单组件

interface InfoTableProps extends TableProps {
  fields: InfoTableField[];
  filterGroups?: [string[]];
}

const InfoTable: FC<InfoTableProps> = ({ fields, filterGroups, ...rest }) => {
  const handleSubmit = (event: FormEvent) => {
    event.preventDefault()
    console.log('button change')
  }

  return (
    <InfoTableForm onSubmit={handleSubmit}>
      {filterGroups?.map((filters) => (
        <ButtonGroup key={getUniqueId()} labels={filters} />
      ))}
      <Table {...rest}>
        <TableBody>
          {fields.map(({ head, value }) => (
            <BodyTableRow key={getUniqueId()}>
              <TableCell component='th'>
                {head}
              </TableCell>
              <TableCell>
                {value instanceof Date ? value.toLocaleDateString() : value}
              </TableCell>
            </BodyTableRow>
          ))}
        </TableBody>
      </Table>
    </InfoTableForm>
  )}

export default InfoTable

解决方案

核心思路

  1. 固定key值:放弃使用getUniqueId()作为key,改用数组索引或稳定标识,避免组件每次渲染都重新挂载,导致事件绑定异常。
  2. 统一按钮类型为submit:不再动态切换按钮类型,而是通过点击逻辑判断是否需要触发提交:
    • 点击已激活按钮时,阻止默认提交行为;
    • 点击未激活按钮时,先更新激活状态,再允许提交事件正常触发。

修改后的ButtonGroup组件

interface ButtonGroupProps {
  labels: string[];
}

const ButtonGroup: FC<ButtonGroupProps> = ({ labels }) => {
  const [active, setActive] = useState<number>(0);

  const handleClick = (index: number) => (e: React.MouseEvent<HTMLButtonElement>) => {
    // 点击已激活按钮,阻止重复提交
    if (active === index) {
      e.preventDefault();
      return;
    }
    // 点击未激活按钮,更新激活状态
    setActive(index);
  }

  return (
    <GroupWrapper>
      {labels.map((label, index) => (
        <Button
          key={index} // 改用索引作为稳定key
          text={label} 
          borderRadius='16px' 
          padding='2px 12px' 
          borderWidth='2px'
          variant={active === index ? 'contained' : 'outlined'}
          type='submit' // 统一为submit类型
          onClick={handleClick(index)}
        />
      ))}
    </GroupWrapper>
  )
}

export default ButtonGroup

修改后的表单组件(仅key部分)

// ...其他代码不变
{filterGroups?.map((filters, groupIndex) => (
  <ButtonGroup key={groupIndex} labels={filters} />
))}
// ...表格行key改为索引
{fields.map(({ head, value }, fieldIndex) => (
  <BodyTableRow key={fieldIndex}>
    <TableCell component='th'>
      {head}
    </TableCell>
    <TableCell>
      {value instanceof Date ? value.toLocaleDateString() : value}
    </TableCell>
  </BodyTableRow>
))}

方案解释

  • 固定key:使用数组索引作为key(若labels不会动态增删,索引是稳定的),保证组件不会因key变化频繁卸载重建,避免事件绑定丢失或异常。
  • 统一submit类型:所有按钮保持submit类型,点击时先判断状态:
    • 已激活按钮:阻止默认提交,避免重复触发;
    • 未激活按钮:更新激活状态后,表单会自动触发onSubmit,不会影响正常提交流程。

这样既实现了点击同一按钮不重复提交,又保证了切换按钮时正常触发表单提交,同时解决了之前onSubmit无法触发的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:45:42