asmith9294
asmith9294

Reputation: 65

Settings states on dynamically filled table rows in React

I'm making a program to make a grocery list. I have a list of possible options in a database on MongoDB, and use it to dynamically fill a table. I want to be able to then use a button to push the food name and quantity to a different collection that will be the list of current groceries I need. I'm having trouble changing the quantity of one item without it happening to every row. Here are snippets of my code:

const [list, setList] = useState([])
const [food, setFood] = useState('')
const [quantity, setQuantity] = useState(
    new Array(list.length).fill(1)
)

useEffect(() => {
    fetch('/api/foods', {
        method: 'GET'
    })
        .then((response) => response.json())
        .then((data) => setList(data))
}, [])

This part fetches the list of all foods.

<tbody>
   {list.map((item, i) => {
            return (
                <tr className="itemRow" key={`foodItem-${i}`}>
                <td className="foodName">
                    {item.food}
                </td>
                <td className="foodQuantity">
                    <input type="number" id="quantity" value={quantity[i]} onChange={((e) => setQuantity(e.target.value))} />
                </td>
                <td className="btn">
                    <button type="button" onClick={((e) => {
                        e.preventDefault()
                        setFood(item.food)
                        fetch('/api/list', {
                            method: 'POST',
                            headers: {
                                'Accept': 'application/json',
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({grocery: food, quantity: quantity.value })
                        })})}>
                    Add</button>
                </td>
            </tr>
        )})
    }
</tbody>

This is where my rows are generated. My 2 problems are: changing the quantity on one changes it on all, and also my push is not working, they are not actually being added to the database.

Upvotes: 0

Views: 41

Answers (1)

Giovanni Esposito
Giovanni Esposito

Reputation: 11176

I see 2 major issues:

  • quantity initialization: at component's first render, list is an empty array (taht will be filled on fetch return ok but quantity is already initialized). So first of all I would suggest you to initialize quantity after you get values from fetch. Something like:

    useEffect(() => {
      fetch('/api/foods', {
          method: 'GET'
      })
          .then((response) => response.json())
          .then((data) => {
             setList(data);
             setQuantity(new Array(data.length).fill(1));
          })
    }, [])
    
  • setQuantity(e.target.value) on input: as @DBS said, in this way you "overwriting the array with a single value". To solve this, just make another function that takes new value and index of element to update. Something like:

    ...
    const handleQuantity = (value, index) => {
       let result = [...list]; //make a copy of list
       result[index] = value;  //assign new value
       setQuantity(result);    //update quantity
    }
    ...
    <input type="number" id="quantity" value={quantity[i]} onChange={((e) => handleQuantity(e.target.value, i))} />
    ...
    

This should solve your problem.

Upvotes: 1

Related Questions