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

React Table单元格添加单选按钮求助:选中状态异常与默认选中失效

解决React Table中行内单选按钮的两个问题

问题根源分析

  1. 行内单选按钮互斥:所有行的单选按钮共用了同一个name="radio"属性,浏览器会将它们归为同一组,导致选中某一行的按钮时,其他行的同组按钮会自动取消选中。
  2. button1默认选中失效:当前用全局的info.length判断按钮选中状态,而非针对当前行的id是否存在于info数组中,逻辑完全错误,导致默认状态下按钮选中表现异常。
  3. 事件处理逻辑错误:handleRadioButton1Change直接清空整个info数组,不符合"仅移除当前行id"的需求;tableData中错误执行了事件处理函数而非传递引用。

修改后的完整代码

CustomRadioButtonComponent.tsx

import React from 'react';
import { Flex, RadioButton } from '你的UI库路径';

interface SomeProps {
  id: string | number;
  info: (string | number)[];
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
  onRadioButton1Change: (id: string | number) => void;
  onRadioButton2Change: (id: string | number, checked: boolean) => void;
}

const CustomRadioButtonComponent: React.FC<SomeProps> = ({
  id,
  info,
  onBlur,
  onRadioButton1Change,
  onRadioButton2Change,
}) => {
  // 判断当前行的选中状态:button1选中 = id不在info数组中
  const isButton1Checked = !info.includes(id);
  // button2选中 = id在info数组中
  const isButton2Checked = info.includes(id);

  const handleRadioButton1Change = React.useCallback(() => {
    onRadioButton1Change(id);
  }, [id, onRadioButton1Change]);

  const handleRadioButton2Change = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
    onRadioButton2Change(id, event.target.checked);
  }, [id, onRadioButton2Change]);

  return (
    <Flex flex={1}>
      <RadioButton
        name={`radio-${id}`} {/* 每行使用独立的name,避免组内互斥 */}
        id={`btn1-${id}`}
        label="button1"
        onChange={handleRadioButton1Change}
        onBlur={onBlur}
        checked={isButton1Checked}
      />
      <RadioButton
        name={`radio-${id}`} {/* 与同组button1使用相同的动态name */}
        id={`btn2-${id}`}
        label="button2"
        checked={isButton2Checked}
        onChange={handleRadioButton2Change}
        onBlur={onBlur}
      />
    </Flex>
  );
};

export default CustomRadioButtonComponent;

main.tsx

import React from 'react';
import { Table, Column, ColumnWithId } from 'react-table';
import CustomRadioButtonComponent from './CustomRadioButtonComponent';

interface Data {
  id: string | number;
  // 其他数据字段
}

interface MainStepProps {
  values: Record<string, any>;
  setFieldValue: (key: string, value: any) => void;
  data: Data[];
  allInfoMap: Record<string | number, string | number>;
  // 其他props
}

const mainStep: React.FC<MainStepProps> = ({ values, setFieldValue, data, allInfoMap }) => {
  const INFO_KEY = 'info';
  const info = values[INFO_KEY] || []; // 确保info是数组,避免undefined

  // 切换到button1时,移除当前行id
  const handleRadioButton1Change = React.useCallback((id: string | number) => {
    const actualId = allInfoMap[id] ?? id;
    setFieldValue(INFO_KEY, info.filter(item => item !== actualId));
  }, [info, setFieldValue, allInfoMap]);

  // 切换到button2时,添加/移除当前行id(使用函数式更新避免闭包问题)
  const handleRadioButton2Change = React.useCallback((id: string | number, checked: boolean) => {
    const actualId = allInfoMap[id] ?? id;
    setFieldValue(INFO_KEY, prevInfo => {
      if (checked) {
        // 避免重复添加
        if (!prevInfo.includes(actualId)) {
          return [...prevInfo, actualId];
        }
        return prevInfo;
      } else {
        return prevInfo.filter(item => item !== actualId);
      }
    });
  }, [setFieldValue, allInfoMap]);

  const columns: Column<Data>[] = [
    {
      Header: 'Name',
      id: 'name',
      accessor: 'name', // 假设data中有name字段
    } as ColumnWithId<Data>,
    {
      Header: 'Radio buttons',
      id: 'radioButtons',
      Cell: ({ row: { selectState, original } }) => {
        // 仅当行被选中时显示按钮
        if (selectState === 1) {
          return (
            <CustomRadioButtonComponent
              id={original.id}
              info={info}
              onRadioButton1Change={handleRadioButton1Change}
              onRadioButton2Change={handleRadioButton2Change}
            />
          );
        }
        return null;
      },
    },
    {
      Header: 'Version',
      accessor: 'version', // 假设data中有version字段
    },
  ];

  // 无需在tableData中注入事件函数,直接在Cell中使用全局处理函数即可
  const tableData = React.useMemo(() => data, [data]);

  return (
    <Table<Data>
      data={tableData}
      columns={columns}
    />
  );
};

export default mainStep;

关键修改点说明

  1. 独立单选按钮组:给每行的单选按钮设置动态name={radio-${id}},确保每行的按钮组相互独立,不会跨行互斥。
  2. 正确的选中状态判断:基于当前行id是否存在于info数组中判断按钮选中状态,默认情况下info为空,所有行的button1都会被选中。
  3. 修复事件逻辑:
    • handleRadioButton1Change改为仅移除当前行的id,而非清空整个数组。
    • handleRadioButton2Change使用函数式更新setFieldValue(prevInfo => ...),避免闭包导致的旧数据问题。
  4. 简化tableData:无需在数据中注入事件函数,直接在Cell组件中引用全局处理函数即可,减少不必要的渲染依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 13:03:11