当表格中某一行的某一列数据变动时,优化性能的关键是最小化重渲染范围。以下是优化方案:
性能优化方案对比
| 优化策略 | 实现方式 | 适用场景 | 效果 |
|---|
| 精确更新 | 只更新变动的单元格 | 单元格独立更新 | ⭐⭐⭐⭐⭐ |
| 行级更新 | 只更新变动的行 | 行内多列联动 | ⭐⭐⭐⭐ |
| 虚拟列表 | 只渲染可视区域 | 大数据量表格 | ⭐⭐⭐⭐⭐ |
| 状态细粒度化 | 每个单元格独立状态 | 频繁局部更新 | ⭐⭐⭐⭐ |
方案 1:单元格级别优化(最推荐)
// 1. 使用独立的单元格组件
const TableCell = React.memo(({ cellId, value }) => {
console.log(`Cell ${cellId} rendered`);
return <td>{value}</td>;
});
// 2. 表格组件
const OptimizedTable = ({ data }) => {
const [cellValues, setCellValues] = useState(data);
// 只更新特定单元格
const updateCell = (rowIndex, colIndex, newValue) => {
setCellValues(prev => {
const newData = [...prev];
// 创建新的行对象
newData[rowIndex] = {
...newData[rowIndex],
[colIndex]: newValue,
};
return newData;
});
};
return (
<table>
<tbody>
{cellValues.map((row, rowIndex) => (
<TableRow
key={row.id}
row={row}
rowIndex={rowIndex}
onUpdateCell={updateCell}
/>
))}
</tbody>
</table>
);
};
// 3. 行组件也进行 memo
const TableRow = React.memo(({ row, rowIndex, onUpdateCell }) => {
return (
<tr>
{Object.entries(row).map(([key, value], colIndex) => (
<TableCell
key={`${rowIndex}-${colIndex}`}
cellId={`${rowIndex}-${colIndex}`}
value={value}
/>
))}
</tr>
);
});
方案 2:使用 Redux/Zustand 状态管理(细粒度更新)
// 使用 Zustand 存储每个单元格的状态
const useTableStore = create(set => ({
cells: {},
updateCell: (rowId, colId, value) =>
set(state => ({
cells: {
...state.cells,
[`${rowId}-${colId}`]: value,
},
})),
}));
// 订阅单个单元格的组件
const SmartCell = ({ rowId, colId }) => {
const value = useTableStore(state => state.cells[`${rowId}-${colId}`]);
const updateCell = useTableStore(state => state.updateCell);
return <input value={value} onChange={e => updateCell(rowId, colId, e.target.value)} />;
};
方案 3:虚拟列表 + 单元格优化
import { FixedSizeGrid as Grid } from "react-window";
const VirtualTable = ({ data, columns }) => {
const Cell = ({ columnIndex, rowIndex, style }) => {
// 只有这个单元格会重新渲染
const cellValue = data[rowIndex][columns[columnIndex]];
return (
<div style={style}>
<EditableCell rowIndex={rowIndex} columnIndex={columnIndex} value={cellValue} />
</div>
);
};
return (
<Grid
columnCount={columns.length}
columnWidth={100}
height={500}
rowCount={data.length}
rowHeight={35}
width={800}
>
{Cell}
</Grid>
);
};