Search code examples
javascriptreactjsuse-effectuse-state

Can't send data to a useState array and map the array in React


I use an API in React to get few objects and I save data to a useState array called 'products'. Each product from products lists has a button called 'Add to cart'. When this button is triggered, the product disapears from the list and is added to cart ( to a second useState array called 'addedProducts')

I have 2 problems here:

  1. When I click "Add to cart", the first element from products list is not added to the secondary list.
  2. Second map function for showing added products is not triggered and don't show the objects from secondary list "addedProducts".

Code:

import { useEffect, useState } from 'react';
import './App.css';

function App() {

  const [products, setProducts] = useState([]);
  const [addedProducts, setAddedProducts] = useState([]);

  useEffect(() => {
    async function getData() {
      const res = await fetch("URL");
      const data = await res.json();
      data.sort((a, b) => a.price > b.price ? 1 : -1);
      data.reverse();
      setProducts(data);
    }

    let unmounted = false;
    if (!unmounted) {
      getData();
    }

    return () => unmounted = true;
  }, []);

  function addProduct(id) {
    document.getElementById(`product_${id}`).style.display = 'none';
    setAddedProducts(products[id]);
    console.log(addedProducts)
  }

  return (
    <div className="App">
      <div className='all'>
        <div>
          <div className="box">
            <div className='checkout'>Checkout page</div>
            <hr />
            {Boolean(products.length) && products.map((product, index) => (
              <div key={index} className='display' id={"product_"+index}>
                <div className='middle'>{product.name}</div>
                <div className='middle'>Price: <span className='price'>${product.price}</span></div>
                <div className='addButton' onClick={(e) => addProduct(index)}>Add to cart</div>
              </div>
            ))}
          </div>
        </div>
        <div className='box2'>
          <div className='noProducts'>No products in your shopping cart</div>
          {Boolean(addedProducts.length) && addedProducts.map((product,index) => {
            <div key={index}>
              {product.price}
            </div>
          })}
        </div>
      </div>
    </div>
  );
}

export default App;

Can anybody tell me what is wrong, please?

This is how my page looks

My page looks like that

EDIT: I couldn't map because on map function I used {} instead of () for creating a div element.


Solution

  • Just a small update on previously given answers. Put the console log outside the addProduct function. Inside the App function body. Otherwise you won't see the updated addedProducts.

    function App() {
    
       ...
    
      function addProduct(id) {
        document.getElementById(`product_${id}`).style.display = 'none';
        setAddedProducts([...addedProducts, products[id]]);
      }
    
      console.log(addedProducts)
    
      return (
       ...
      );
    }
    
    export default App;
    

    Update your second array as follows. If addedProducts state does contain elements. Then it shouldn't show ''No products in your shopping cart''

            <div className="box2">
              {addedProducts.length > 0 ? (
                addedProducts.map((product, index) => {
                  <div key={index}>{product.price}</div>;
                })
              ) : (
                <div className="noProducts">No products in your shopping cart</div>
              )}
            </div>