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

React DevExtreme DataGrid批量编辑模式下获取单元格变更列与新值问题

React DevExtreme DataGrid 批量+虚拟滚动模式下获取单元格变更信息

问题描述

使用React DevExtreme DataGrid,开启**批量编辑(batch)和虚拟滚动(virtual scrolling)**模式,尝试onKeyDown、onColumnsChange、onEditingChange等事件均无法获取变更的列及新值;使用onChangesChange函数但效果不符合预期。

相关代码如下:

DataGrid组件代码

<DataGrid
  scrolling={{ mode: "virtual" }}
  id={'id'}
  dataSource={dataDateGrid}
  onKeyDown={handleKeyDown}
  onColumnsChange={val => {
    console.log('onColumnsChange', val)
  }}
  onEditingChange={val => {
    console.log('onEditingChange', val)
  }}
>
  <Editing
    mode="batch"
    allowUpdating
  />
</DataGrid>

尝试的handleChangesChange函数

const handleChangesChange = (changes: any) => {
  if (changes.length > 0) {
    // 尝试通过对比之前的变更记录找最新变更
    const latestChange = changes.find(
      (change: any) => !previousChangesRef.current.includes(change)
    );

    if (latestChange) {
      const { type, data, key, oldData } = latestChange;

      if (type === 'update') {
        // 遍历data找变更列
        for (const column in data) {
          console.log('column: ', column);
          console.log('data: ', data);
        }
      }

      previousChangesRef.current = changes;
    }
  }
}

解决方案

1. 正确绑定onChangesChange事件

首先要确保在DataGrid上正确绑定onChangesChange事件,补全组件属性:

<DataGrid
  scrolling={{ mode: "virtual" }}
  id={'id'}
  dataSource={dataDateGrid}
  // 绑定变更监听事件
  onChangesChange={handleChangesChange}
>
  <Editing
    mode="batch"
    allowUpdating
  />
</DataGrid>

2. 修正handleChangesChange逻辑

原代码通过includes对比变更项的方式不可行,因为每次变更后changes数组内的对象是新引用,无法通过引用匹配。正确做法是对比变更的key和类型,筛选出新增的变更:

import { useRef } from 'react';

// 用ref存储上次的变更记录
const previousChangesRef = useRef<any[]>([]);

const handleChangesChange = (currentChanges: any[]) => {
  // 筛选出当前变更中未在上次记录出现的项
  const newChanges = currentChanges.filter(currentChange => {
    return !previousChangesRef.current.some(prevChange => {
      return prevChange.key === currentChange.key && prevChange.type === currentChange.type;
    });
  });

  newChanges.forEach(change => {
    if (change.type === 'update') {
      // 对比oldData和data,找出真正变更的列
      const changedColumns = Object.keys(change.data).filter(column => {
        return change.data[column] !== change.oldData[column];
      });

      changedColumns.forEach(column => {
        console.log(`变更列:${column}`);
        console.log(`新值:${change.data[column]}`);
        console.log(`旧值:${change.oldData[column]}`);
        console.log(`行唯一标识:${change.key}`);
      });
    }
  });

  // 更新上次变更记录,注意解构避免引用同步
  previousChangesRef.current = [...currentChanges];
};

3. 备选方案:实时监听单元格编辑

如果需要在用户输入过程中实时获取变更(无需等待单元格失焦),可以通过onEditorPreparing绑定编辑器的onValueChanged事件:

<DataGrid
  scrolling={{ mode: "virtual" }}
  id={'id'}
  dataSource={dataDateGrid}
  onEditorPreparing={(e) => {
    if (e.parentType === 'dataRow' && e.dataField) {
      // 保留编辑器原有逻辑
      const originalOnValueChanged = e.editorOptions.onValueChanged;
      e.editorOptions.onValueChanged = (args) => {
        originalOnValueChanged?.(args);
        // 输出变更信息
        console.log(`变更列:${e.dataField}`);
        console.log(`新值:${args.value}`);
        console.log(`旧值:${args.previousValue}`);
        console.log(`当前行数据:${e.row.data}`);
      };
    }
  }}
>
  <Editing
    mode="batch"
    allowUpdating
  />
</DataGrid>

注意事项

  • 虚拟滚动模式下,onEditorPreparing仅在单元格编辑器创建时触发,符合按需渲染的逻辑。
  • 批量模式下,onChangesChange会在单元格编辑完成(如失焦、按回车)时触发,收集所有未提交的变更记录。

内容的提问来源于stack exchange,提问作者alaa-sufi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:28:19