I am trying to implement OnClick inside the renderBody as shown in the code snippet. I need it to enable deletion of any record using it's id. I have the Table component handling table rows, data and pagination. The handleDelete function is inside the Main Component, Trials. I need to implement a call to handleDelete function for every row I want to delete.
Adding itdirectly to renderBody gives an error "undefined handleDelete..." How can I add handleDelete function on every table row dynamically inside the renderBody?
import React from 'react'
const renderBody = (item, index) => (
<tr key={index}>
<td>{item.sn}</td>
<td>{item.names}</td>
<td>{item.gender}</td>
<td>{item.regno}</td>
<td>{item.email}</td>
<td>{item.phone}</td>
<td>
<div className='flex-action'>
<button
className='btn-text'
title={`View More Information`}
onClick={ } //how to add an onClick function here
><i className="bx bx-list-ol" size={30} >Delete</i>
</button>
</div>
</td>
</tr>
)
const data = [
{
id: 1,
name: "IphoneX",
img:
"https://didongviet.vn/pub/media/catalog/product//i/p/iphone-x-mau-xam-didongviet.jpg"
},
{
id: 2,
name: "Samsung Fold",
img:
"https://images.samsung.com/pk/smartphones/galaxy-z-fold3-5g/buy/zfold3_carousel_mainsinglekv_mo.jpg"
},
{
id: 3,
name: "Laptop Gaming",
img:
"https://cdn.techzones.vn/Data/Sites/1/News/3285/techzones-nhung-mau-laptop-gaming-choi-game-co-tan-nhiet-tot-nhat-tren-thi-truong.jpg"
}
];
const Trials = () => {
const [users, setUsers] = useState([])
const [products, setProducts] = useState(data);
//You can put all product information into diaglog
const [dialog, setDialog] = useState({
message: "",
isLoading: false,
//Update
nameProduct: ""
});
const idProductRef = useRef();
const handleDialog = (message, isLoading, nameProduct) => {
setDialog({
message,
isLoading,
//Update
nameProduct
});
};
const handleDelete = (id) => {
//Update
const index = data.findIndex((p) => p.id === id);
handleDialog("Are you sure you want to delete?", true, data[index].names);
idProductRef.current = id;
};
const areUSureDelete = (choose) => {
if (choose) {
setProducts(products.filter((p) => p.id !== idProductRef.current));
handleDialog("", false);
} else {
handleDialog("", false);
}
};
return (
<div className="card__body">
{
users.length > 0 ? (
<Table
limit='20'
headData={customerTableHead}
renderHead={(item, index) => renderHead(item, index)}
bodyData={users}
renderBody={(item, index) => renderBody(item, index)}
/>
) :
(
<h3>No search results</h3>
)
}
{
dialog.isLoading && (
<Dialog
//Update
nameProduct={dialog.nameProduct}
onDialog={areUSureDelete}
message={dialog.message}
/>
)
}
</div>
)
}
export default Trials
CodePudding user response:
You can move your renderBody
definition within your Trials
component, so that handleDelete
is within scope. Additionally, use useCallback
so that renderBody
doesn't have to be constructed every time you render.
import React from 'react'
const data = [ REMOVED_FOR_COMPACTNESS ];
const Trials = () => {
const [users, setUsers] = useState([])
const [products, setProducts] = useState(data);
//You can put all product information into diaglog
const [dialog, setDialog] = useState({
message: "",
isLoading: false,
//Update
nameProduct: ""
});
const idProductRef = useRef();
const handleDialog = (message, isLoading, nameProduct) => {
setDialog({
message,
isLoading,
//Update
nameProduct
});
};
const handleDelete = (id) => {
//Update
const index = data.findIndex((p) => p.id === id);
handleDialog("Are you sure you want to delete?", true, data[index].names);
idProductRef.current = id;
};
const areUSureDelete = (choose) => {
if (choose) {
setProducts(products.filter((p) => p.id !== idProductRef.current));
handleDialog("", false);
} else {
handleDialog("", false);
}
};
// will only create the callback whenever your users state changes,
// for performance
// fyi renaming "item" to "user" would be clearer
const renderBody = useCallback((item, index) => (
<tr key={index}>
<td>{item.sn}</td>
<td>{item.names}</td>
<td>{item.gender}</td>
<td>{item.regno}</td>
<td>{item.email}</td>
<td>{item.phone}</td>
<td>
<div className='flex-action'>
<button
className='btn-text'
title={`View More Information`}
// we now have access to handleDelete, since we're defined within the componenet
onClick={ () => handleDelete(item.id) }
><i className="bx bx-list-ol" size={30} >Delete</i>
</button>
</div>
</td>
</tr>
), [users])
return (
<div className="card__body">
{
users.length > 0 ? (
<Table
limit='20'
headData={customerTableHead}
renderHead={(item, index) => renderHead(item, index)}
bodyData={users}
renderBody={renderBody}
// you can just pass the function, like above, since it
// already takes 2 arguments. No need for an arrow function
// old: renderBody={(item, index) => renderBody(item, index)}
/>
) :
(
<h3>No search results</h3>
)
}
{
dialog.isLoading && (
<Dialog
//Update
nameProduct={dialog.nameProduct}
onDialog={areUSureDelete}
message={dialog.message}
/>
)
}
</div>
)
}
export default Trials