Reputation: 545
This is my first time using react-table, after I decided to redesign a component in my app. I'm almost there, but I found myself stuck while trying to pass some data to a dialog pop-up on button click.
In my previous table design, using MUI Table, I used array.map()
to render each row entry. Then, all I needed to do was using props
to pass data to the Dialog
components, so every action button would load the data from their respective entries (including data not displayed, like _id
). Now with react-table I don't know how to achieve the same result, due to the logic change. The Edit and Delete buttons are there, they trigger the dialog opening, but my progress ends here.
Entries.jsx
function Entries(props) {
const navigate = useNavigate();
const [openEdit, setOpenEdit] = useState(false);
const [openDelete, setOpenDelete] = useState(false);
const handleEdit = () => {
setOpenEdit(true);
};
const handleDelete = () => {
setOpenDelete(true);
};
const handleClose = () => {
setOpenEdit(false);
setOpenDelete(false);
};
const data = props.data;
const columns = useMemo(
() => [
{
Header: "#",
id: "row",
Cell: ({ row }) => {
return <div>{row.index + 1}</div>;
},
},
{
Header: "Title",
accessor: "title",
className: "column-left",
Cell: ({ cell: { value }, row: { original } }) => (
<Link
sx={{
fontSize: "14px",
fontWeight: 500,
"&:hover": { color: "#00D67E" },
}}
color="#fff"
underline="none"
style={{ cursor: "pointer" }}
onClick={() => navigate(`/details/${original.movieId}`)}
>
{value}
</Link>
),
},
{
Header: "Year",
accessor: "year",
className: "column-right",
},
{
Header: "Rating",
accessor: "details[0].rating",
className: "column-right",
Cell: ({ cell: { value } }) => (
<Rating
size="small"
value={value}
readOnly
emptyIcon={<StarIcon fontSize="inherit" />}
/>
),
},
{
Header: "Watched",
accessor: "date",
className: "column-right",
Cell: ({ cell: { value } }) => format(new Date(value), "MMM dd, yyyy"),
},
{
Header: "View Count",
accessor: "details[0].view_count",
className: "column-right",
},
{
Header: "Review",
accessor: "details[0].review",
className: "column-right",
Cell: ({ cell: { value } }) =>
!value ? null : <CheckIcon color="primary" />,
},
{
Header: "Actions",
className: "column-right",
Cell: () => (
<div>
<IconButton
aria-label="edit"
style={{ color: "#e0e0e0" }}
onClick={handleEdit}
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
aria-label="delete"
style={{ color: "#e0e0e0", paddingRight: 0 }}
onClick={handleDelete}
>
<DeleteIcon fontSize="small" />
</IconButton>
</div>
),
},
],
[]
);
return (
<div>
{/* TABLE */}
<CustomTable columns={columns} data={data} />
{/* DIALOGS */}
<EditDialog
isOpen={openEdit}
onClose={handleClose}
id={data._id}
movieId={data.movieId}
date={data.date}
rating={data.details[0].rating}
review={data.details[0].review}
onUpdate={props.onUpdate}
/>
<DeleteDialog
isOpen={openDelete}
onClose={handleClose}
title="Delete this entry?"
message={
<span>
<strong>
{data.title} ({data.date})
</strong>{" "}
will be removed. This action cannot be undone.
</span>
}
onRemove={() => {
props.onRemove(data._id, data.movieId);
}}
/>
</div>
);
}
export default Entries;
Later on I even tried something to mimic the logic of my previous design, since the mapping is handled by the rows.map((row) => { prepareRow(row) }
in my CustomTable.jsx
component. Then I came up with this:
{
Header: "Actions",
className: "column-right",
Cell: () => (
<div>
<IconButton
aria-label="edit"
style={{ color: "#e0e0e0" }}
onClick={({row}) => {
handleEdit();
return (
<EditDialog
isOpen={openEdit}
onClose={handleClose}
id={row._id}
movieId={row.movieId}
date={row.date}
rating={row.details[0].rating}
review={row.details[0].review}
onUpdate={props.onUpdate}
/>
);
}}
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
aria-label="delete"
style={{ color: "#e0e0e0", paddingRight: 0 }}
onClick={handleDelete}
>
<DeleteIcon fontSize="small" />
</IconButton>
</div>
),
}
But it didn't work either. It stops right at the first prop and throws an error saying it can't read properties row._id
. That was my last shot.
Upvotes: 3
Views: 7845
Reputation: 974
That is simple, you can store the selected row to the state and then use it in your Edit and Delete components. Try this
function Entries(props) {
const navigate = useNavigate();
const [openEdit, setOpenEdit] = useState(false);
const [openDelete, setOpenDelete] = useState(false);
const [selectedRow, setSelectedRow] = useState();
const handleEdit = (row) => {
setOpenEdit(true);
setSelectedRow(row);
};
const handleDelete = (row) => {
setOpenDelete(true);
setSelectedRow(row);
};
const handleClose = () => {
setOpenEdit(false);
setOpenDelete(false);
setSelectedRow();
};
const data = props.data;
const columns = useMemo(
() => [
{
Header: "#",
id: "row",
Cell: ({ row }) => {
return <div>{row.index + 1}</div>;
}
},
{
Header: "Title",
accessor: "title",
className: "column-left",
Cell: ({ cell: { value }, row: { original } }) => (
<Link
sx={{
fontSize: "14px",
fontWeight: 500,
"&:hover": { color: "#00D67E" }
}}
color="#fff"
underline="none"
style={{ cursor: "pointer" }}
onClick={() => navigate(`/details/${original.movieId}`)}
>
{value}
</Link>
)
},
{
Header: "Year",
accessor: "year",
className: "column-right"
},
{
Header: "Rating",
accessor: "details[0].rating",
className: "column-right",
Cell: ({ cell: { value } }) => (
<Rating
size="small"
value={value}
readOnly
emptyIcon={<StarIcon fontSize="inherit" />}
/>
)
},
{
Header: "Watched",
accessor: "date",
className: "column-right",
Cell: ({ cell: { value } }) => format(new Date(value), "MMM dd, yyyy")
},
{
Header: "View Count",
accessor: "details[0].view_count",
className: "column-right"
},
{
Header: "Review",
accessor: "details[0].review",
className: "column-right",
Cell: ({ cell: { value } }) =>
!value ? null : <CheckIcon color="primary" />
},
{
Header: "Actions",
className: "column-right",
Cell: ({ row }) => (
<div>
<IconButton
aria-label="edit"
style={{ color: "#e0e0e0" }}
onClick={() => handleEdit(row.original)}
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
aria-label="delete"
style={{ color: "#e0e0e0", paddingRight: 0 }}
onClick={() => handleEdit(row.original)}
>
<DeleteIcon fontSize="small" />
</IconButton>
</div>
)
}
],
[]
);
return (
<div>
{/* TABLE */}
<CustomTable columns={columns} data={data} />
{/* DIALOGS */}
<EditDialog
isOpen={openEdit}
onClose={handleClose}
id={selectedRow?._id}
movieId={selectedRow?.movieId}
date={selectedRow?.date}
rating={selectedRow?.details[0]?.rating}
review={selectedRow?.details[0]?.review}
onUpdate={props.onUpdate}
/>
<DeleteDialog
isOpen={openDelete}
onClose={handleClose}
title="Delete this entry?"
message={
<span>
<strong>
{selectedRow?.title} ({selectedRow?.date})
</strong>{" "}
will be removed. This action cannot be undone.
</span>
}
onRemove={() => {
props.onRemove(selectedRow?._id, selectedRow?.movieId);
}}
/>
</div>
);
}
export default Entries;
Upvotes: 2