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

React Table onClick事件中选中状态值异常,始终与实际状态相反

问题:选中行时handleClick中isItemSelected值与实际状态相反

我用Material-UI的Table展示版本数据,点击行时控制台输出的isItemSelected总是和实际选中状态相反——选中行时显示false,取消选中时显示true,但我需要它和当前选中状态一致。相关代码如下:

Table渲染代码

const [selected, setSelected] = React.useState<readonly number[]>([]);
const isSelected = (id: number) => selected.indexOf(id) !== -1;

return (
<TableContainer>
             <Table sx={{ width: "100%" }}>
               {listVersions
                 ? listVersions.map((current_version, index) => {
                     const isItemSelected = isSelected(index+ 1);
                     const labelId = `enhanced-table-checkbox-${index}`;
                     return (
                       <TableRow
                         hover
                         onClick={() => handleClick(index + 1, current_version, isItemSelected)}
                         role="checkbox"
                         aria-checked={isItemSelected}
                         tabIndex={-1}
                         key={index + 1}                         
                         selected={isItemSelected}
                         sx={{ cursor: "pointer" }}
                       >
                         <TableCell padding="checkbox">
                           <Checkbox
                             color="primary"
                             checked={isItemSelected}
                             inputProps={{
                               "aria-labelledby": labelId,
                             }}
                           />
                         </TableCell>
                         <TableCell>{current_version}</TableCell>
                       </TableRow>
...
);

handleClick函数代码

const handleClick = (id: number, version: string, isItemSelected: boolean) => {
  console.log(version , isItemSelected); // 此处isItemSelected值异常:选中行时为false,期望为true
 const selectedIndex = selected.indexOf(id);
    let newSelected: readonly number[] = [];

    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, id);
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1));
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1));
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(
        selected.slice(0, selectedIndex),
        selected.slice(selectedIndex + 1),
      );
    }
    setSelected(newSelected);
} 

问题原因

核心问题是状态更新的异步性:你在TableRow的onClick中传递的isItemSelected是组件渲染时的旧状态(也就是点击前的状态)。当触发handleClick时,React还没完成selected状态的更新,所以控制台打印的是点击前的状态值,自然和你预期的“点击后的状态”相反。

举个例子:

  • 行未选中时,isItemSelected为false,点击后状态会变为选中,但你打印的是点击前的false,看起来像“选中时显示false”;
  • 行已选中时,isItemSelected为true,点击后状态会变为未选中,但你打印的是点击前的true,看起来像“取消选中时显示true”。

解决方案

方案1:在handleClick内计算预期状态

不需要传递isItemSelected,直接在函数内根据当前selected数组判断,取反得到点击后的预期状态:

const handleClick = (id: number, version: string) => {
  // 判断当前行是否已选中
  const isCurrentlySelected = selected.includes(id);
  // 点击后的预期状态是当前状态的取反
  const expectedIsSelected = !isCurrentlySelected;
  console.log(version, expectedIsSelected); // 现在与实际操作一致

  let newSelected: readonly number[] = [];
  if (!isCurrentlySelected) {
    newSelected = [...selected, id];
  } else {
    newSelected = selected.filter(itemId => itemId !== id);
  }
  setSelected(newSelected);
}

同时修改TableRow的onClick,移除isItemSelected参数:

onClick={() => handleClick(index + 1, current_version)}

方案2:简化状态更新逻辑(可选优化)

你之前的newSelected分情况处理的逻辑可以简化,用函数式更新更简洁:

const handleClick = (id: number, version: string) => {
  const isCurrentlySelected = selected.includes(id);
  const expectedIsSelected = !isCurrentlySelected;
  console.log(version, expectedIsSelected);

  setSelected(prevSelected => 
    isCurrentlySelected 
      ? prevSelected.filter(item => item !== id) 
      : [...prevSelected, id]
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:45:22