I am learning React and now I am making a very basic shopping list app. I wanted to increment the amount of existing items in the list, instead of adding duplicating items (with the same name).
I have the following component:
import React, { useState } from 'react';
import ShoppingForm from './ShoppingForm';
import ShoppingList from './ShoppingList';
function Shopping() {
const [shoppingList, setShoppingList] = useState([]);
const addHandler = ({title, amount}) => {
const existingIndex = shoppingList.findIndex(item => item.title === title);
const item = shoppingList[existingIndex];
if (item) {
item.amount = item.amount + amount;
setShoppingList( prevShoppingList => [ ...prevShoppingList.slice(0, existingIndex), item, ...prevShoppingList.slice(existingIndex + 1) ] );
} else {
setShoppingList( prevShoppingList => [...prevShoppingList, {id: Math.random().toString(), title, amount}] );
}
};
const removeHandler = (removeId) => {
const fIlteredList = shoppingList.filter(item => item.id !== removeId);
setShoppingList(fIlteredList);
};
return (
<div className="App">
<ShoppingForm onAddItem={addHandler}/>
<section>
<ShoppingList items={shoppingList} onRemoveItem={removeHandler}/>
</section>
</div>
);
}
export default Shopping;
It works. However, I am wondering if there’s a more intuitive/easier to read way of writing this line
setShoppingList( prevShoppingList => [ ...prevShoppingList.slice(0, existingIndex), item, ...prevShoppingList.slice(existingIndex + 1) ] );
I tried to use something like just setShoppingList(items)
but this way the child component ShoppingList
doesn’t update amounts, unless a new item is added to the list or an existing item is removed, then the amount for what’s left on the list get updated as well.
This is my shopping list component:
import React from 'react';
import classes from './ShoppingList.module.css';
const ShoppingList = (props) => {
return (
<section className={classes['shopping-list']}>
<h2>Shopping List:</h2>
<ul>
{props.items.map(item => (
<li key={item.id} onClick={props.onRemoveItem.bind(this, item.id)}>
{/* <span>{item.id}</span> */}
<span>{item.title}</span>
<span>{item.amount}x</span>
</li>
))}
</ul>
</section>
);
};
export default ShoppingList;
2
Answers
You can shorten your construct with toSpliced method: