skip to Main Content

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


  1. const addHandler = ({ title, amount }) => {
      const updatedList = shoppingList.map(item => {
        if (item.title === title) {
          return {
            ...item,
            amount: item.amount + amount
          };
        }
        return item;
      });
    
      setShoppingList(updatedList);
    };
    
    Login or Signup to reply.
  2. You can shorten your construct with toSpliced method:

    setShoppingList(prevShoppingList => [ ...prevShoppingList.toSpliced(existingIndex, 1, item)]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search