Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛[BUG] EditableProTable 结合 proForm 使用,在表格头部插入数据时,导致其他数据丢失 #6572

Open
ZhangJiL opened this issue Feb 7, 2023 · 4 comments
Labels
AI Reply ⭕️ bug Something isn't working table

Comments

@ZhangJiL
Copy link

ZhangJiL commented Feb 7, 2023

提问前先看看:

https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md

🐛 bug 描述

EditableProTable 结合 proForm 使用,在表格头部插入数据时,导致其他数据丢失

📷 复现步骤

🏞 期望结果

💻 复现代码

参考 sandbox

© 版本信息

  • ProComponents 版本: [e.g. 4.0.0]
  • umi 版本
  • 浏览器环境
  • 开发环境 [e.g. mac OS]

🚑 其他信息

423582ad2fd39a25492f4ef882c2d390

@chenshuai2144 chenshuai2144 added ⭕️ bug Something isn't working table labels Feb 8, 2023
@gogomusic
Copy link

删除时也有此问题

@chenshuai2144
Copy link
Contributor

TAutomatically replying with ChatGPT can be attempted, but it cannot be guaranteed to be completely accurate and may not fully address all issues. Please feel free to reply if you have any further questions or concerns.
此回复基于 ChatGPT 自动生成,可以尝试下方案,官方员会在一定时间后继续继续处理。

从您提供的信息和截图来看,问题出现在通过 ProForm 的表单项来添加、修改和删除 EditableProTable 数据时,并且机制是通过 Redux 存储数据,同时在删、增、改某行数据的时候,其他行数据内容丢失。

可能原因:

EditableProTable 组件使用了 redux 作为数据存储机制,从数据流架构上分析,应该是在数据分发时,造成了数据的更新错误,导致某些行数据呈 “空” 状态。

解决方案:

  • 确认在添加、修改和删除 EditableProTable 数据时,使用了正确的 Redux 存储机制,如果Redux已经使用正确,则跳过此步骤。
  • 尝试使用可变性数据结构(如 immutability-helper 和 Immer.js)。在 Redux 中,为了避免直接操作和改变数据存在的问题(如深层嵌套和浅层复制),推荐使用可变性结构。以下列举了一些可变性结构的使用文档及代码示例:
  1. immutability-helper:Github地址:https://github.com/kolodny/immutability-helper;使用文档:https://github.com/kolodny/immutability-helper#readme

  2. Immer.js:Github地址:https://github.com/immerjs/immer;使用文档:https://immerjs.github.io/immer/docs/introduction

代码示例:您可以尝试使用 Immer.js 实现带有 Redux 的 EditableProTable。如下:

在你的 reducer 中:

import produce from "immer";

// 其他设置...

const reducer = produce((draftState, action) => {
  switch (action.type) {
    case "addRow":
       // 这里是逻辑代码
       // 此处使用 Immer.js
       const newData = { title: "测试标题", desc: "测试描述" };
       draftState.dataSource = [...draftState.dataSource, newData];
       break;

    case "updateRow":
       const { rowIndex, columnName, columnValue } = action.payload;
       // 这里也使用 Immer.js,设置新的 dataSource
       draftState.dataSource = draftState.dataSource.map((item, index) => {
         if (index === rowIndex) {
           return { ...item, [columnName]: columnValue };
         }
         return item;
       });
       break;

    case "deleteRow":
       const { rowIndex } = action.payload;
       // 删除一个row调用Immer.js
       draftState.dataSource = draftState.dataSource.slice(rowIndex);
       break;

    default:
      return draftState;
  }
});

export default reducer;

在您的 EditableProTable 组件中:

import { EditableProTable } from "@ant-design/pro-table";
import { produce } from "immer";

const Page: React.FC<PageProps> = () => {
  const [dataSource, setDataSource] = useState([]);

  const actionRef = useRef<ActionType>();

  const reducer = useReducer<Reducer<PageState, PageActions>>(pageReducer, {
    //初始化dataSource和其他状态
    dataSource: [],
    loading: false,
    count: 2
  });

  const handleRowDelete = (rowIndex: number) => {
    const [state, dispatch] = reducer;
    dispatch({ type: "deleteRow", payload: { rowIndex } });
  };

  const handleUpdateRow = (rowIndex: number, columnName: string, columnValue: string) => {
    const [state, dispatch] = reducer;
    dispatch({ type: "updateRow", payload: { rowIndex, columnName, columnValue } });
  };

  const handleRowAdd = () => {
    const [state, dispatch] = reducer;

    dispatch({ type: "addRow" });
  };

  //封装组件逻辑
  const handleTableRowChange = (
    list: PageState["dataSource"],
    record: PageState["dataSource"][0],
    _, //没有变化的列值
    action: string
  ) => {
    switch (action) {
      case "update":
        const { index, key, value } = record;
        console.log("update", { index, key, value });
        handleUpdateRow(index, key, value);
        break;
      case "delete":
        const { index } = record;
        console.log("delete", index);
        handleRowDelete(index);
        break;
      default:
        break;
    }

    setDataSource(list);
  };

  return (
    <Form>
      <ProFormList
        name="users"
        creatorButtonProps={{
          position: "top",
          creatorButtonText: "新增一行",
          max: 5,
          onCreator: handleRowAdd
        }}
        itemRender={(item, { list, action }, index) => {
          return (
            <Form.Item>
              <EditableProTable
                rowKey="index"
                columns={[
                  {
                    title: "标题",
                    dataIndex: "title",
                    //此处设置一个编辑框
                    renderFormItem: () => <Input />
                  },
                  {
                    title: "描述",
                    dataIndex: "desc",
                    // 此处必须设置为textarea,否则过长的字符串会出现无法编辑的错误
                    renderFormItem: () => <TextArea rows={1} />
                  }
                ]}
                value={list}
                onChange={(newList) => handleTableRowChange(newList, list, action)}
                onDelete={(a, record) => handleTableRowChange(a, record, action, "delete")}
                recordCreatorProps={false}
              />
            </Form.Item>
          );
        }}
      ></ProFormList>
    </Form>
  );
};

通过改用 Immer.js,你可以简化你的 reducer 操作,生成可读性更高的代码,同时,也可以优化内存的使用,减少可能存在的无谓的数据复制。

希望以上方案可以帮到您,若有不明白的地方或遇到新问题,请在评论中详细描述,并附上代码和相关参数,以便于问题精确定位和排查。

@liushuhui
Copy link

我也遇到了,只能通过这种方式吗

@liushuhui
Copy link

@chenshuai2144

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AI Reply ⭕️ bug Something isn't working table
Projects
None yet
Development

No branches or pull requests

4 participants