Home > Software engineering >  TypeError: "count" is read-only. The count is assigned once, but the second time no
TypeError: "count" is read-only. The count is assigned once, but the second time no

Time:11-20

When I add a product to my cart(for the first time), action.payload.count = 1; works fine in my slice. But when I clear my cart(added item is removed), and again add that(the same product), I get this error in the console and item doesn't add to the cart:

Uncaught TypeError: "count" is read-only addToCart CartSlice.js:13

It doesn't have any error when I add a new product(it's not removed before).

Why are products added correctly the first time, but not added again after deletion?

cartSlice.js

export const CartSlice = createSlice({
    name: "cart",
    initialState: [],
    reducers: {
        addToCart(state, action){
            const existIndex = state.findIndex(item => item.shortName === action.payload.shortName);
            if(existIndex !== -1){
                state[existIndex].count  = 1;
            }
            else{
                action.payload.count = 1;
                state.push(action.payload);
            }
        },
        clearCart(state, action){
            return state=[];
        }
    }
})

card.js

export const Card = ({product, showProductSlide}) => {
    const dispatch = useDispatch();
    const addToCart = () => {
        dispatch({type: "cart/addToCart", payload: product})
    }

    return(
        <div className="card item border-0 overflow-hidden">
            <div className="img-box">
                <img src={product.pic} className="card-img-top" alt="..." />
                <div className="triangle"></div>
            </div>
                <div className="card-body d-flex flex-column justify-content-between bg-secondary text-white">
                    <p className="card-text">{product.shortName}</p>
                    <p className="card-text text-end fw-bold">{product.price}</p>
                    <div className="d-flex justify-content-between">
                        <button className="btn btn-sm bg-transparent text-white" onClick={showProductSlide}><span className="q-mark me-1">?</span>Quick-view</button>
                        <button className="btn btn-sm bg-transparent btn-cart text-nowrap" onClick={addToCart}>Add to cart<div><span> </span></div></button>
                    </div>
                </div>
        </div>
    )
}

cartList.js

export const CartList = ({showCart, cartProducts}) => {
    const dispatch = useDispatch();

    const totalPrices = () => {
        let total = 0;
        cartProducts.forEach(function (value){
            total  = Number(value.price.replace(/[$]/, "")) * value.count;
        })
        return total.toFixed(2);
    }
    const clearCart = () => {
        dispatch({type: "cart/clearCart", payload: ""})
    }

    return(
        <div className={showCart ? "open-list" : "close-list"}>
            {cartProducts.length === 0 ?
                <span className="align-self-center">empty</span> :
                <>
                    <ul>
                        {cartProducts.map((item, index) => {
                                return(
                                    <li className="d-flex justify-content-between" key={index}>
                                        <span>{item.shortName}</span><span>{item.count}</span>
                                    </li>
                                )
                            }
                        )}
                    </ul>
                    <p className="total-price">Total Amounts: {totalPrices()}</p>
                    <button onClick={clearCart}>Cancel order</button>
                </>
            }
        </div>
    )
}

Link to output: https://eloquent-kashata-a64506.netlify.app/

Please do these: Click add to cart, then clear cart, and again add the same product.

CodePudding user response:

Actually it is always a bad idea to mutate action parameter of your reducer. In your case each time you do this, you change your cart product.

I'd suggest using spread operator and create shallow copy of action payload state.push({ ...action.payload, count: 1 }).

CodePudding user response:

Can't directly mutate the action payload. assign payload to a variable and change

 else{
   const obj = {...action.payload}
   obj.count = 1;
   state.push(obj);
 }
  • Related