0

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

CLICK HERE

case appConstants.DELETE_IMAGE_SUCCESS:
  return {
    ...state,
    products: state.productImages.filter((item) => item !== action.payload)
  };

3 Answers 3

1

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>
  );
// ...

CodeSandbox

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. shouldnt we use useCallback, memo etc... to avoid rerendering?
0

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.

7 Comments

Let's just assume the imageFileName is unique. could you fork my codesandbox? Thanks!
In that case, this should solve it for you. I copied this code and pasted it into your sandbox, replacing the existing case statement, and it appears to work as expected.
shouldnt we use useCallback, memo etc... to avoid rerendering?
Hooks like useCallback are only for components and other hooks; your reducer is not inside a component or a hook, so no.
Yes. but what I mean is on the function onDeleteImage
|
0

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

2 Comments

@Joseph, check this out!!
Thank you. shouldnt we use useCallback, memo etc... to avoid rerendering?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.