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

React中DevExpress DataGrid子数组附件的表单编辑实现求助

React中DevExpress DataGrid编辑模式下实现子数组增删改

问题背景

我在React中使用DevExpress DataGrid,数据结构包含attachments子数组,示例数据如下:

{
  id: 2,
  attachments: [
    {attachmentId: 1001, mandatory: true, name: "ordine"}, 
    {attachmentId: 1002, mandatory: true, name: "ordine 2"}
  ]
  // 其他字段...
}

希望在form编辑模式下,实现该子数组的添加、删除、编辑功能。尝试自定义AttachmentDataGrid组件但无任何显示效果,现求助可行的实现代码。

我尝试的自定义组件代码

interface Props {
    data: any
}

export const AttachmentDataGrid : React.FC<Props> = ({ data } : Props) => {
  const [ attachments, setAttachments ] = useState<any[]>([]);

  useEffect(() => {
    setAttachments(data.value);
  }, []);

  const onValueChanged = (e : any) => {
    data.setValue(e.value);
  }

  const onSelectionChanged = () => {
    data.component.updateDimensions();
  }

  return <>
            <GroupItem caption="Attachment"
              name="phones-container">
                  { attachments.map((att, index) => {
                      return <GroupItem
                      name="attachments"> 
                       <Label text={`Attachments ${index + 1}`} />
                       {att.name}
                                  <SimpleItem dataField={`attachments[${index}].name`} />
                                  <SimpleItem dataField={`attachments[${index}].mandatory`} />
                      </GroupItem>
                    })}
              <SimpleItem itemType="button"
                cssClass="add-attachment-button"
                 onClick={() => { console.log('add-attachment') }}> 
                >
              </SimpleItem>
            </GroupItem>
         
          </> 
  
}

可行实现方案

修正后的自定义附件组件

import React, { useState, useEffect } from 'react';
import { GroupItem, SimpleItem, Label, Button } from 'devextreme-react/form';

interface Attachment {
  attachmentId?: number;
  mandatory: boolean;
  name: string;
}

interface Props {
  data: {
    value: Attachment[];
    setValue: (value: Attachment[]) => void;
    component: any;
  };
}

export const AttachmentEditor: React.FC<Props> = ({ data }) => {
  const [attachments, setAttachments] = useState<Attachment[]>([]);

  // 监听数据源变化,同步本地状态
  useEffect(() => {
    setAttachments(data.value || []);
  }, [data.value]);

  // 同步本地状态到form数据源
  useEffect(() => {
    data.setValue(attachments);
    data.component?.updateDimensions();
  }, [attachments, data]);

  // 添加新附件
  const handleAddAttachment = () => {
    setAttachments([...attachments, { mandatory: false, name: '' }]);
  };

  // 删除指定索引的附件
  const handleDeleteAttachment = (index: number) => {
    const updated = attachments.filter((_, i) => i !== index);
    setAttachments(updated);
  };

  // 更新单个附件字段
  const handleFieldChange = (index: number, field: keyof Attachment, value: any) => {
    const updated = [...attachments];
    updated[index][field] = value;
    setAttachments(updated);
  };

  return (
    <GroupItem caption="附件列表" name="attachments-group">
      {attachments.map((att, index) => (
        <GroupItem
          key={index}
          name={`attachment-${index}`}
          cssClass="attachment-item"
        >
          <Label text={`附件 ${index + 1}`} />
          <SimpleItem>
            <input
              type="text"
              value={att.name}
              onChange={(e) => handleFieldChange(index, 'name', e.target.value)}
              placeholder="输入附件名称"
              style={{ width: '100%', padding: '8px' }}
            />
          </SimpleItem>
          <SimpleItem>
            <label>
              <input
                type="checkbox"
                checked={att.mandatory}
                onChange={(e) => handleFieldChange(index, 'mandatory', e.target.checked)}
              />
              必填
            </label>
          </SimpleItem>
          <SimpleItem itemType="button">
            <Button
              text="删除"
              onClick={() => handleDeleteAttachment(index)}
              stylingMode="outlined"
              type="danger"
            />
          </SimpleItem>
        </GroupItem>
      ))}
      <SimpleItem itemType="button">
        <Button
          text="添加附件"
          onClick={handleAddAttachment}
          stylingMode="contained"
          type="default"
        />
      </SimpleItem>
    </GroupItem>
  );
};

在DataGrid编辑表单中使用该组件

import React from 'react';
import DataGrid, { Column, Editing, Form } from 'devextreme-react/data-grid';
import { AttachmentEditor } from './AttachmentEditor';

// 示例数据源
const sampleData = [
  {
    id: 2,
    attachments: [
      { attachmentId: 1001, mandatory: true, name: "ordine" },
      { attachmentId: 1002, mandatory: true, name: "ordine 2" }
    ],
    // 其他字段...
  }
];

export const App = () => {
  return (
    <DataGrid
      dataSource={sampleData}
      keyExpr="id"
    >
      <Column dataField="id" caption="ID" />
      {/* 其他列 */}
      <Editing
        mode="form"
        allowUpdating={true}
        allowAdding={true}
      >
        <Form>
          {/* 其他表单字段 */}
          <AttachmentEditor data={{
            value: sampleData[0].attachments,
            setValue: (newValue) => {
              sampleData[0].attachments = newValue;
              // 如果使用状态管理,这里需要更新数据源状态
            },
            component: null // 可以传递form组件实例,用于更新尺寸
          }} />
        </Form>
      </Editing>
    </DataGrid>
  );
};

关键修复点说明

  • 修复了useEffect未监听data.value变化的问题,确保本地状态和数据源同步
  • 实现了完整的增删改逻辑,通过本地状态更新后同步到form数据源
  • 替换了原错误的dataField写法,改为直接绑定输入控件到本地状态
  • 修正了按钮组件的语法错误,使用DevExpress的Button组件替代原生按钮
  • 添加了类型定义,提升代码可维护性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:01:11