I have an item inside an array of an array and I want to target it and delete it. My problem is how do I access it and delete that particular item without mutating it.
Codesandbox is here
case appConstants.DELETE_IMAGE_SUCCESS:
return {
...state,
products: state.productImages.filter((item) => item !== action.payload)
};
CodePudding user response:
You should pass an additional payload - product
. So that we can find the target product in state.products
array by productCode
. Suppose ProductCode
can Identity a product.
Only use imageFileName
is unable to determine which product it belongs to.
case appConstants.DELETE_IMAGE_SUCCESS:
console.log(state);
const nState = {
...state,
products: state.products.map((item) => {
if (item.productCode !== action.payload.product.productCode)
return item;
return {
...item,
productImages: item.productImages.filter(
(v) => v.imageFileName !== action.payload.imageFileName
)
};
})
};
console.log(nState);
return nState;
App.js
:
// ...
const onDeleteImage = (imageFileName, product) => {
dispatch(deleteImage({ imageFileName, product }));
};
return (
<div className="App">
{(products || []).map((product, index) => (
<ProductCard
product={product}
key={index}
onDeleteImage={(imageFileName) =>
onDeleteImage(imageFileName, product)
}
/>
))}
</div>
);
// ...
CodePudding user response:
Here's the conceptual solution:
case appConstants.DELETE_IMAGE_SUCCESS:
return {
...state,
products: state.products.map(product => ({
...product,
productImages: (product.productImages ?? [])
.filter(({imageFileName}) => imageFileName !== action.payload),
})),
};
Caveat: if more than one product has an image with the same file name as the one you are deleting, it will be deleted from the other products as well. (This is currently a limitation of the information provided in your payload.) If that description is a bug for your program, then you'll need to also provide a product ID in the payload so that you only filter images for the matching product.
CodePudding user response:
You need to pass productIndex
or id
along with the imageFileName
to correctly do the delete. Otherwise, all the products having the same imageFileName
will be deleted.
Try this
case appConstants.DELETE_IMAGE_SUCCESS:
return {
...state,
products: (state.products || []).map((item, itemIndex) => {
if (itemIndex === action.payload.productIndex) {
return {
...item,
productImages: item.productImages.filter(
(image) => image.imageFileName !== action.payload.imageFileName
)
};
}
return item;
})
};
In App.js file
const onDeleteImage = (productIndex, imageFileName) => {
dispatch(deleteImage(productIndex, imageFileName));
};
in actions index.js file
export const deleteImage = (productIndex, imageFileName) => {
return {
type: appConstants.DELETE_IMAGE_SUCCESS,
payload: {
productIndex,
imageFileName
}
};
};
In MediaCard.js file
<Button
type="button"
color="primary"
variant="contained"
onClick={() => onDeleteImage(productIndex, data.imageFileName)}
>
Code sandbox => https://codesandbox.io/s/redux-added-array-of-object-inside-another-aray-in-react-forked-xmghr?file=/src/reducers/productReducer.js