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

React实现单个按钮点击独立切换状态的解决方案

解决按钮状态同步变化的问题

你的核心问题是用了一个全局布尔状态selected控制所有按钮和行的状态,导致点击任意按钮都会触发全局状态变更,所有元素同步变化。要实现单个按钮独立控制,需要跟踪单个选中商品(单选)或选中商品集合(多选),以下是两种场景的解决方案:

单选场景(一次选一个商品)

修改状态逻辑,用单个变量跟踪当前选中的商品,点击按钮时切换选中状态:

import React from 'react';
import { useState } from 'react';
import 'bulma/css/bulma.css';
import './App.scss';

export const goods = [
  'Dumplings',
  'Carrot',
  'Eggs',
  'Ice cream',
  'Apple',
  'Bread',
  'Fish',
  'Honey',
  'Jam',
  'Garlic',
];

export const App: React.FC = () => {
  // 跟踪当前选中的商品,null表示未选中
  const [selectedItem, setSelectedItem] = useState<string | null>(null);

  const handleChange = (good: string) => {
    // 点击已选中的商品则取消,否则选中该商品
    setSelectedItem(prev => prev === good ? null : good);
  }

  const clearAll = () => {
    setSelectedItem(null);
  }

  return (
    <main className="section container">
      {selectedItem === null && (
        <h1 className="title">No goods selected</h1>
      )}

      {selectedItem !== null && (
        <h1 className="title is-flex is-align-items-center">
          {selectedItem + ' is selected'}
          <button
            data-cy="ClearButton"
            type="button"
            className="delete ml-3"
            onClick={clearAll}
          />
        </h1>
      )}

      <table className="table">
        <tbody>
          {goods.map((good) => (
            <tr
              data-cy="Good"
              key={good}
              className={selectedItem === good ? "has-background-success-light" : ""}
            >
              <td>
                <button
                  data-cy="AddButton"
                  type="button"
                  className="button"
                  onClick={() => handleChange(good)}
                >
                  {selectedItem === good ? '-' : '+'}
                </button>
              </td>
              <td
                data-cy="GoodTitle"
                className="is-vcentered"
              >
                {good}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </main>
  )
}

关键修改点

  • 移除全局selected状态,改用selectedItem跟踪单个选中商品
  • handleChange直接接收商品名称,判断是否已选中来切换状态
  • 按钮文本和行样式均基于当前商品是否等于selectedItem
  • 修正onClick传参问题:原代码误将事件对象当作商品名称传递,现在直接传入当前商品

多选场景(可选中多个商品)

如果需要支持多选,用Set存储所有选中的商品,点击按钮时切换商品的选中状态:

import React from 'react';
import { useState } from 'react';
import 'bulma/css/bulma.css';
import './App.scss';

export const goods = [
  'Dumplings',
  'Carrot',
  'Eggs',
  'Ice cream',
  'Apple',
  'Bread',
  'Fish',
  'Honey',
  'Jam',
  'Garlic',
];

export const App: React.FC = () => {
  // 用Set存储选中的商品,保证唯一性
  const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());

  const handleChange = (good: string) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev);
      // 切换商品的选中状态
      newSet.has(good) ? newSet.delete(good) : newSet.add(good);
      return newSet;
    });
  }

  const clearAll = () => {
    setSelectedItems(new Set());
  }

  return (
    <main className="section container">
      {selectedItems.size === 0 && (
        <h1 className="title">No goods selected</h1>
      )}

      {selectedItems.size > 0 && (
        <h1 className="title is-flex is-align-items-center">
          {Array.from(selectedItems).join(', ') + ' selected'}
          <button
            data-cy="ClearButton"
            type="button"
            className="delete ml-3"
            onClick={clearAll}
          />
        </h1>
      )}

      <table className="table">
        <tbody>
          {goods.map((good) => (
            <tr
              data-cy="Good"
              key={good}
              className={selectedItems.has(good) ? "has-background-success-light" : ""}
            >
              <td>
                <button
                  data-cy="AddButton"
                  type="button"
                  className="button"
                  onClick={() => handleChange(good)}
                >
                  {selectedItems.has(good) ? '-' : '+'}
                </button>
              </td>
              <td
                data-cy="GoodTitle"
                className="is-vcentered"
              >
                {good}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </main>
  )
}

关键修改点

  • 用Set<string>存储选中的商品,方便判断和增删操作
  • 修改状态时遵循React不可变原则,复制原Set后再修改
  • 顶部标题显示所有选中的商品,无选中时显示默认文本
  • 按钮和行样式基于当前商品是否存在于selectedItems集合中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:50:24