I'm working on a shopping cart.
<Cart />
is Cart Page which render Products in cartList Array.
<CartProduct />
render each one product in cartList Array
I want to make the quantity data change, when i click quantity button.
Here is My First Try Code
function Cart(props) {
const cartsList = useRecoilValue(cartsListState);
return(
{cartsList
.filter(cart => cart.keep === 'cold')
.map((cart) => {
return <CartProduct cart={cart} getNowQuantity={getNowQuantity} />
})
}
{cartsList
.filter(cart => cart.keep === 'freeze')
.map((cart) => {
return <CartProduct cart={cart} getNowQuantity={getNowQuantity} />
})
}
{cartsList
.filter(cart => cart.keep === 'normal')
.map((cart) => {
return <CartProduct cart={cart} getNowQuantity={getNowQuantity} />
})
}
)
}
function CartProduct({ cart, getNowQuantity}) {
const [cartsList, setCartsList] = useRecoilState(cartsListState);
return(
const PlusQuantity = () => {
setCounterQuantity(counterQuantity => counterQuantity + 1);
cart.quantity += 1;
getNowQuantity(cart.quantity);
}
const MinusQuantity = () => {
if (cart.quantity>=2) {
setCounterQuantity(counterQuantity => counterQuantity - 1);
cart.quantity -= 1;
getNowQuantity(cart.quantity);
}
else return;
}
)
}
Firts code make error
Uncaught TypeError: Cannot assign to read only property 'quantity' of object '#
So i tried to use spread operator in CartProduct.js
Like this way
const cartProduct = ([ ...cart]);
return(
CartProduct.quantity = +1
~~
~~~
)
This code make error
cart is not iterable
so i tried
let iterableCart = cart[Symbol.iterator]
It doesn't work.
How can i change cart.property
for ChangeQuantityButton?
By default Recoil makes everything immutable so code like this
cart.quantity += 1;
won't work because you're trying to update a value on a frozen object.
Instead you need to create a new object, and use the existing values to update it.
Here I'm using a sample data set and using it to build three product items using an <Item>
component. This component displays the name, the current quantity, and two buttons to decrement/increment the values. On the buttons are a couple of data attributes that identify the product id, and the button action.
When a button is clicked the handleClick
function is called. This destructures the id
and action
from the button dataset, and then map
over the current cart using those values to check the cart items and return updated objects to the state.
const { atom, useRecoilState, RecoilRoot } = Recoil;
// Initialise the cart data
const cart = [
{ id: 1, name: 'Banana', qty: 0 },
{ id: 2, name: 'Beef', qty: 0 },
{ id: 3, name: 'Mop', qty: 0 }
];
// Initialise the cart atom setting its
// default to the cart data
const cartAtom = atom({
key: 'cartAtom',
default: cart
});
function Example() {
// Use the recoil state
const [ cart, setCart ] = useRecoilState(cartAtom);
// When a button is clicked
function handleClick(e) {
// Get its id and action
const { dataset: { id, action } } = e.target;
// Update the cart using the id to identify the item
// and return an updated object where appropriate
setCart(prev => {
return prev.map(item => {
if (item.id === +id) {
if (action === 'decrement' && item.qty > 0) {
return { ...item, qty: item.qty - 1 };
}
if (action === 'increment') {
return { ...item, qty: item.qty + 1 };
}
}
return item;
});
});
}
// Iterate over the cart data using the Item
// component to display the item details
return (
<div>
{cart.map(item => {
const { id, name, qty } = item;
return (
<Item
key={id}
id={id}
name={name}
qty={qty}
handleClick={handleClick}
/>
);
})}
</div>
);
}
function Item({ id, name, qty, handleClick }) {
return (
<div className="item">
<span className="name">{name}</span>
<button
data-id={id}
data-action="decrement"
type="button"
onClick={handleClick}
>-
</button>
{qty}
<button
data-id={id}
data-action="increment"
type="button"
onClick={handleClick}
>+
</button>
</div>
);
}
ReactDOM.render(
<RecoilRoot>
<Example />
</RecoilRoot>,
document.getElementById('react')
);
.item:not(:last-child) { margin-bottom: 0.25em; }
.name { display: inline-block; width: 60px; }
button { width: 30px; height: 30px; margin: 0 0.25em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/recoil@0.7.6/umd/index.js"></script>
<div id="react"></div>