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

React/TypeScript按钮组添加移除类名的正确实现方法

你当前的问题是每个ActiveBtn组件都独立维护了一套布尔类型的激活状态,不同组件实例的状态完全隔离,因此无法实现同组按钮互斥激活的效果。要实现同一时间仅一个按钮激活的效果,需要将激活状态从单个按钮组件提升到按钮组的父层级统一管理。

改造步骤

1. 优化基础Button组件(可选,仅修复冗余类型定义)

import React from 'react';
import './Button.scss';

interface ButtonProps {
    children: React.ReactNode;
    onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
    variant: string;
    className?: string;
}

const Button: React.FunctionComponent<ButtonProps> = (props: ButtonProps) => {
    return (
        <button 
            type="button" 
            onClick={props.onClick} 
            className={`btn-${props.variant} ${props.className || ''}`}
        >
            {props.children}
        </button>
    )
}

export default Button;

2. 封装统一管理状态的ButtonGroup组件

通过唯一ID标记每个按钮,在组层级统一记录当前激活的按钮ID,点击时切换ID即可自动实现互斥效果:

import React from 'react';
import Button from './Button';

interface ButtonGroupItem {
  id: string | number; // 每个按钮的唯一标识
  label: React.ReactNode;
}

interface ButtonGroupProps {
  items: ButtonGroupItem[];
  defaultActiveId?: string | number;
  onChange?: (activeId: string | number) => void;
}

const ButtonGroup: React.FC<ButtonGroupProps> = (props) => {
  const { items, defaultActiveId, onChange } = props;
  const [activeId, setActiveId] = React.useState(defaultActiveId ?? items[0]?.id);

  const handleClick = (id: string | number) => {
    setActiveId(id);
    onChange?.(id);
    // 原有alert逻辑可放在此处,或通过onChange自定义业务逻辑
  }

  return (
    <div className="button-group">
      {items.map(item => (
        <Button
          key={item.id}
          variant={activeId === item.id ? 'tertiary-active' : 'tertiary'}
          onClick={() => handleClick(item.id)}
        >
          {item.label}
        </Button>
      ))}
    </div>
  )
}

export default ButtonGroup;

3. 业务组件中调用

const Page = () => {
  // 示例:渲染3个互斥激活的按钮
  return (
    <ButtonGroup
      items={[
        { id: 'btn1', label: '按钮1' },
        { id: 'btn2', label: '按钮2' },
        { id: 'btn3', label: '按钮3' }
      ]}
      defaultActiveId="btn1"
      onChange={(activeId) => console.log('当前激活按钮ID:', activeId)}
    />
  )
}

如果不需要封装通用按钮组,也可以直接在父组件声明激活状态,逐个传给Button组件即可:

const Page = () => {
  const [activeId, setActiveId] = React.useState('btn1');
  return (
    <div>
      <Button
        variant={activeId === 'btn1' ? 'tertiary-active' : 'tertiary'}
        onClick={() => setActiveId('btn1')}
      >
        按钮1
      </Button>
      <Button
        variant={activeId === 'btn2' ? 'tertiary-active' : 'tertiary'}
        onClick={() => setActiveId('btn2')}
      >
        按钮2
      </Button>
      <Button
        variant={activeId === 'btn3' ? 'tertiary-active' : 'tertiary'}
        onClick={() => setActiveId('btn3')}
      >
        按钮3
      </Button>
    </div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:24:03