在 React Ag-Grid 中,如果用户一次将数据粘贴到多个单元格中,则会为粘贴的每个单元格调用 valueSetter。这会显着减慢渲染速度,因为如果用户想要粘贴到 10 个单元格中,则 valueSetter 会被调用 10 次(我的 Ag-Grid 中的数据是使用 redux 管理的,因此当 Ag-Grid 中发生更改时我必须调度更新) 。理想情况下,valueSetter 可以对所有更改进行分组,然后只被调用一次。
这是我的 onChange 函数:
const onChange = (params) => {
const uuid = params.data['UUID'];
var newValue = params.newValue;
const field = params.colDef.field;
const updates = [{tableName: props.tableName, newValues: [newValue], updateColumnNames:[field], uuids:[uuid]}];
dispatch(updateTableMulti(updates));
}
onChange函数通过columndDefinition参数与每一列关联,如
colDefs.push({'field': colName,
'headerName': columnHeader,
...,
'valueSetter': (params) => {onChange(params); return true},
headerTooltip: headerTooltip,
...type
})
我尝试使用 AgGridReact 的 onPasteStart 和 onPasteEnd 参数来指示 onChange 何时应将更新分组在一起,但是,onChange 函数在 onPasteStart 注册之前就被调用了。
嗯,这并不漂亮,但我确实找到了解决我自己的问题的方法。 AgGridReact 对象接受参数 processDataFromClipboard,它允许您构建一个函数,在处理粘贴的数据之前对其进行编辑。我使用此函数向粘贴的值添加一些元数据,指示我应该批量处理粘贴的数据,而不是一次一个。
如果有人有更优雅的答案,我会欢迎。
这是我的代码的相关部分:
const CLIPBOARD_INDICATOR = generateUUID(); // this is used to indicate that the bulk update is in progress
const CLIPBOARD_END_INDICATOR = '_END'; // this is used to indicate that the bulk update is complete
const DataEntryTable = (props) => {
const DEFAULT_BULK_UPDATE = {tableName: props.tableName, newValues: [], updateColumnNames:[], uuids:[]}
const [bulkUpdates, setBulkUpdates] = useState(DEFAULT_BULK_UPDATE);
const onChange = (params) => {
const uuid = params.data['UUID'];
var newValue = params.newValue;
var isBulkUpdate = false;
var submitBulk = false;
if (Array.isArray(newValue)) {
if (newValue.length > 1) {
if (newValue[newValue.length - 2] == CLIPBOARD_INDICATOR) {
isBulkUpdate = true;
if (newValue[newValue.length - 1] == CLIPBOARD_END_INDICATOR) {
submitBulk = true;
}
newValue = newValue[0]
}
}
}
}
if (isBulkUpdate) {
bulkUpdates['newValues'].push(newValue);
bulkUpdates['updateColumnNames'].push(field);
bulkUpdates['uuids'].push(uuid);
if (submitBulk) {
dispatch(updateTableMulti(bulkUpdates));
setBulkUpdates(DEFAULT_BULK_UPDATE);
}
} else {
const updates = {tableName: props.tableName, newValues: [newValue], updateColumnNames:[field], uuids:[uuid]};
dispatch(updateTableMulti(updates));
}
function processDataFromClipboard (params) {
const clipboardData = params.data;
// for each entry in params.data, add the clipboard indicator to the end of the array
clipboardData.forEach((row, row_idx) => {
row = [row[0], CLIPBOARD_INDICATOR];
if (row_idx == clipboardData.length - 1) {
// on the last entry, add the end indicator
row.push(CLIPBOARD_END_INDICATOR);
}
});
return clipboardData;
}
return (
<AgGridReact
onChange={(params) => onChange(params)}
processDataFromClipboard={(params) => processDataFromClipboard(params)}
{...otherProps}
/>
)
};