material-table 在编辑行中打开对话框关闭行编辑后

material-table after open dialog in edit row is closed edit of row

我在 Reactjs 库中使用 material-table。我有一个用于使用对话框添加图像的列按钮。它适用于添加新行,但如果我想在打开对话框 关闭行编辑后编辑行 。我认为这个问题可能是由重新渲染引起的。

打开编辑行

单击按钮后打开了添加图​​像的对话框,但行的编辑已结束,我无法保存更改。

import { Button, Container, IconButton } from "@material-ui/core";
import MaterialTable from "@material-table/core";
import React, { useState } from "react";
import { DropzoneDialogBase } from "material-ui-dropzone";
import CloseIcon from "@material-ui/icons/Close";
import { tableIcons } from "./IconProvider";

const App = () => {
  const [equipment, setEquipment] = useState([{url: '', name: 'Test'}]);
  const [open, setOpen] = useState(false);
  const [image, setImage] = useState([]);

  const FILES_LIMIT = 1;
  const pageSize = [10, 20, 50, 100];

  const dialogTitle = () => (
    <>
      <span>Upload file</span>
      <IconButton
        style={{ right: "12px", top: "8px", position: "absolute" }}
        onClick={() => setOpen(false)}
      >
        <CloseIcon />
      </IconButton>
    </>
  );

  return (
    <Container maxWidth={"xl"}>
      <MaterialTable
        columns={[
          {
            field: "url",
            title: "Url",
            editComponent: () => (
              <Button
                variant="contained"
                color="primary"
                onClick={() => setOpen(true)}
              >
                {"Add image"}
              </Button>
            ),
            render: (rowData) => <img src={rowData.url} />
          },
          { field: "name", title: "Name" }
        ]}
        data={equipment}
        title={"Title"}
        options={{
          pageSizeOptions: pageSize,
          pageSize: pageSize[0]
        }}
        icons={tableIcons}
        editable={{
          onRowAdd: (newData) =>
            new Promise((resolve, reject) => {
              setTimeout(() => {
                setEquipment([...equipment, newData]);

                resolve();
              }, 1000);
            }),
          onRowUpdate: (newData, oldData) =>
            new Promise((resolve, reject) => {
              setTimeout(() => {
                const dataUpdate = [...equipment];
                const index = oldData.tableData.id;
                dataUpdate[index] = newData;
                setEquipment([...dataUpdate]);

                resolve();
              }, 1000);
            }),
          onRowDelete: (oldData) =>
            new Promise((resolve, reject) => {
              setTimeout(() => {
                const dataDelete = [...equipment];
                const index = oldData.tableData.id;
                dataDelete.splice(index, 1);
                setEquipment([...dataDelete]);

                resolve();
              }, 1000);
            })
        }}
      />

      <DropzoneDialogBase
        dialogTitle={dialogTitle()}
        acceptedFiles={["image/*"]}
        fileObjects={image}
        cancelButtonText={"cancel"}
        submitButtonText={"submit"}
        maxFileSize={5000000}
        filesLimit={FILES_LIMIT}
        open={open}
        onAdd={(newFileObjs) => {
          setImage([].concat([], newFileObjs));
        }}
        onDelete={(deleteFileObj) => {
          setImage(image.filter((item) => item !== deleteFileObj));
        }}
        onClose={() => setOpen(false)}
        onSave={() => {
          setOpen(false);
        }}
        showPreviews={true}
        showFileNamesInPreview={true}
      />
    </Container>
  );
};

export default App;

我在 Codesandbox

创建了考试

你是对的,问题发生是因为你在每次状态更新时触发重新渲染,当提供给 material table 的列是静态的,但包含在每次渲染时更新的函数时,就会发生这种情况,重置 table 状态。提供 stable 函数或列引用或行 ID 以防止状态丢失。

所以,你修复的是:

  const preventRerender = useCallback((rowData) => <img src={rowData.url} />, []);
  const editComponent = useCallback(() => {
    return <Button
      variant="contained"
      color="primary"
      onClick={() => setOpen(true)}
    >
      {"Add image"}
    </Button>;
  }, [])

<MaterialTable
        columns={[
          {
            field: "url",
            title: "Url",
            editComponent,
            render: preventRerender
          },
          { field: "name", title: "Name" }
        ]}

通过添加回调或 useMemo,如果你想通过更新数组依赖,你将阻止更新状态。

补充说明,跟踪并注意行 key/id

Sandbox Demo