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
相关产品推荐
相关产品推荐

