-1

I made a similar question related with arrays and maps but only half got answered which is why I'm making this one apart.

I have this code (Only relevant info):

const [libros, setLibros] = useState([]);
const [cantidad, setCantidad] = useState([1]);

//This is not finished because I'm still stuck
const mas = (index, value) => {
        setCantidad(cantidad[index] + 1);
      };

      const menos = (index, value) => {
        if (cantidad[index] > 0){
            setCantidad(cantidad[index] - 1);
        }
        else {
            window.alert("Sorry, Zero limit reached");
            setCantidad(0);
        }
      };


<tbody>
     {libros.map((l, index) => (
          <tr >
           <td>
               <button onClick = {() => mas(index)}/>
               {cantidad[index]}
               <button onClick = {() => menos(index)}/>
               </td>
               <td>{l.grado}</td>

               <td >
               <input onChange = {(event) => {
               let checked = event.target.checked;
               }} 
               type="checkbox" checked = "">

//I know this check is not working properly I'm strill trying to figure out this one 

               </input>
               {l.descripcion}
               </td>
               <td >{l.editorial}</td>
               <td >${parseFloat(l.precio).toFixed(2) * cantidad[index]}</td>
               </tr>

   ))}
</tbody>

I know that in javascript you can do the following:

Array(5).fill(2)
//=> [2, 2, 2, 2, 2]

Is there a way to do something similar in React? because what I want to achieve is the following: "cantidad" will always start as 1 and then grant the ability to the user to change that amount +1 or -1 depending on how many of an item he/she wants but I do not know how to set up all the values to 1, with that being said, someone already guide me before telling me that by adding the index value on the map I can control them individually I fail to understand how to apply that on my code because I would like to send the current index and the current value of that index to the

const mas = (index, value) => {
        setCantidad(cantidad[index] + 1);
      };

      const menos = (index, value) => {
        if (cantidad[index] > 0){
            setCantidad(cantidad[index] - 1);
        }
        else {
            window.alert("Sorry, Zero limit reached");
            setCantidad(0);
        }
      };

functions that I have made, this is how is printing atm, I kind of understand it how to do it if you already set up an X amount of values in the array but not when the amount of values are based on the amount of times the map repeats I try using map.lenght but didn't work any advice/tips are welcome

enter image description here

This is the whole code

import React, { useState, useEffect } from 'react'
import { auth, db } from './firebase';
import { useHistory } from 'react-router-dom';
import { Checkbox } from '@material-ui/core';

function CrearPedidos({user}) {
    const [libros, setLibros] = useState([]);
    const [cantidad, setCantidad] = useState(new Array(libros.length).fill(1);

    const history = useHistory("");
    const [totalPrice, setTotalPrice] = useState();

    const librosRef = db.collection('libros');
    const queryRef = librosRef.where('grado', '==', '4° Grado');

   console.log(queryRef)

    useEffect(() => {
        queryRef.orderBy("precio")
        .get()
        .then((snapshot) => {
              const tempData = [];
            snapshot.forEach((doc) => {
              const data = doc.data();
              tempData.push(data);
            });
            setLibros(tempData);
          });
      }, []);

      const mas = (index) => {
        setCantidad(cantidad[index] + 1);
      };

      const menos = (index) => {
        if (cantidad[index] > 0){
            setCantidad(cantidad[index] - 1);
        }
        else {
            window.alert("Sorry, Zero limit reached");
            setCantidad(0);
        }
      };

    return (
        <div className="listado_Pedidos"> 
        <div className="estudiantes_container">
            <h1 className = "estudiantes_container_h1">Estudiante: {user.displayName}</h1>
            <h1 className = "estudiantes_container_h1">Libros Nuevos</h1>
            <div className ="tableContainer">
            <table>
                <thead>
                    <tr className="Lista">
                        <th>Cantidad</th>
                        <th>Grado</th>
                        <th>Descripcion</th>
                        <th>Editorial</th>
                        <th>Precio</th>
                    </tr>
                </thead>
                <tbody>
                {libros.map((l, index) => (
                        
                        <tr >
                        
                        <td>
                            <button onClick = {() => mas(index)}/>
                            {cantidad[index]}
                            <button onClick = {() => menos(index)}/>
                        </td>
                        <td>{l.grado}</td>

                        <td >
                        <input onChange = {(event) => {
                            let checked = event.target.checked;
                        }} 
                        
                        type="checkbox" checked = "">
                        </input>
                        {l.descripcion}
                        </td>

                        <td >{l.editorial}</td>
                        <td >${parseFloat(l.precio).toFixed(2) * cantidad[index]}</td>
                        </tr>

                     ))}
                </tbody>
            </table>
            </div>

            <div className="space" />
            <button onClick="{realizarPedidos}" className = "crear_estudiante_boton">Realizar Pedidos</button>
            <div className="space" />
      </div>

      </div>
    )
}

export default CrearPedidos

This is how it looks like and what does cantidad is showing on the logs

enter image description here

ReactPotato
  • 1,262
  • 3
  • 26
  • 46
  • First thing I noticed was `const [cantidad, setCantidad] = useState([1])` then just a little further down: `setCantidad(cantidad[index] + 1);`. Is this intentional? You initialize it as an array (`[]`) with the number `1` but then you're changing the type to a number, not an array. – Steve Hynding Sep 17 '21 at 22:58
  • eh not really my coding skills in React are very crude/bad so I was just trying things. – ReactPotato Sep 17 '21 at 23:22

2 Answers2

1

You can initialize cantidad array depending on libros.length

const [cantidad, setCantidad] = useState( new Array(libros.length).fill(1) );

const mas = (index) => {
  setCantidad(cantidad[index] + 1);
};

const menos = (index, value) => {
  if (cantidad[index] > 0){
    setCantidad(cantidad[index] - 1);
  } else {
    window.alert("Sorry, Zero limit reached");
    setCantidad(0);
  }
};
Steve Hynding
  • 1,799
  • 1
  • 12
  • 22
1

Your setCantidad method usage needs to set a new array that includes the incremented value, not the incremented value of one of its items.

You are initializing useState with an array but later changing it from an array to just the value of one of those items in the array.

To be specific, you are initializing cantidad to be [1] which is the same as new Array(1).fill(1). However, you later set cantidad to be cantidad[index] + 1 which (assuming index is 0) would mean you are changing cantidad from [1] to 2. It went from an array with a number to just a number.

In order to maintain cantidad as an array, you should be setting it with a new array when it changes. setCantidad is simply there to update your state with a new value; it does not know or care what it was initialized with or previously set as.

So, you could update it many ways. Here's one suggestion:

const mas = (index) => {
  cantidad[index] = cantidad[index]++
  // Note how we're setting it with a new array, not the original. 
  // It is important to know how JS references objects (such as arrays) vs other types 
  // by using its pointer as the source of truth vs its pure bytes, respectively
  setCantidad([...cantidad]);
};

const menos = (index, value) => {
  if (cantidad[index] > 0){
    cantidad[index] = cantidad[index]--
    setCantidad([...cantidad]);
  } else {
    window.alert("Sorry, Zero limit reached");
    // no need to do any setting here as the indexed value should already be zero based on the condition above
  }
};
Steve Hynding
  • 1,799
  • 1
  • 12
  • 22
  • Oooh that was what some people was trying to explain but I didn't understand what they meant with setting it back to 1 instead of array, that makes so much sense now. I just have a question what does ```setCantidad([...cantidad])``` means ? like the ```...cantidad``` I'm new to react so... I fail to understand some basic things like that. Any documentation link is appreciate it. I was literally about to make a question for this btw thanks for this! – ReactPotato Sep 19 '21 at 17:22
  • That is called "destructuring assignment" and you can read how that works in detail at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment – Eduardo Hernández Sep 19 '21 at 23:09