'material-table after open dialog in edit row is closed edit of row
I use in Reactjs library material-table. I have for one column button for add image using dialog. It work good for add new row but if i want edit row after open dialog is closed edit of row. I think that problem can be cause with rerender.
After click at button is opened dialog for add image but edit of row is ended and i cant save change.
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;
I create examle at Codesandbox
Solution 1:[1]
You are correct, issue happen since you are trigger rerender on each state update, this happen when the columns provided to material table are static, but contain functions which update on every render, resetting the table state. Provide a stable function or column reference or an row id to prevent state loss.
So, you fix is:
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" }
]}
by adding callback or useMemo you will prevent update state else if you want by update array dependency.
Additional note, keep track and take care about rows key/id
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Anees Hikmat Abu Hmiad |