0

I keep getting this error - Uncaught TypeError: itemList.map is not a function I was under the impression itemList was just supposed to be an array? There is an array being returned in console log for itemList.

The following code is just a popup modal that pulls in data from a users shopping cart.

function Example(props) {
  const [show, setShow] = useState(false);
  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);
  const [itemList, setItemList] = useState('');
  const url = wordpressurl + "checkout/";

  useEffect(() => {
    async function getItems() {
      const value = await localforage.getItem('cart_key');
      await CoCart.get("cart?cart_key=" + value).then((response) => {
        setItemList(response.data.items);
      })
    }
    console.info(itemList);
    if (!itemList) {
      getItems();
    }
  });

  return (
    <>
      <div onClick={handleShow} className='cartlable'>Cart</div><div id="cartcount"><div className="cartcount">0</div></div>
      <Modal show={show} onHide={handleClose}>
        <Modal.Header closeButton className="me-2">
          <Modal.Title>Your Cart</Modal.Title>
        </Modal.Header>
        <Modal.Body id="cartlist">
          <div className="container-fluid">
            <div className="row">
              <div className="col-8 text-start"><h5>ITEM</h5></div>
              <div className="col-1 text-center"><h5>QTY</h5></div>
              <div className="col-2 text-end"><h5>SUBTOTAL</h5></div>
              <div className="col-1 text-end pe-2"></div>
            </div>

            {itemList.map((cartitem) =>
              <div className="row align-middle cartitemrows">
                <div className="col-1 text-start"><img src={cartitem.featured_image} className="cartimage" alt="" />{cartitem}</div>
              </div>
            )}

            <div className="row pt-3"><div className="col-11 text-end"><h5>TOTAL : <span id="carttotal"></span></h5></div></div>
            <form id="form-id" action={url} method="get" encType="multipart/form-data">
              <input type="hidden" name="cocart-load-cart" />
              <button id="your-id">Checkout</button>
            </form>
          </div>
        </Modal.Body>
        <Modal.Footer>
        </Modal.Footer>
      </Modal>
    </>
  );
}

Does anyone know where I'm going wrong? Thanks

Btw this is what shows up in console if I declare the useState as a string instead of an array like so const [itemList, setItemList] = useState([]); -

(2) [{…}, {…}]
0: {item_key: '698d51a19d8a121ce581499d7b701668', id: 111, name: 'Cuff Beanie', title: 'Cuff Beanie', price: '3000', …}
1: {item_key: '7ce9004ae3ad190443d43d7f81241060', id: 107, name: 'Womans T-shirt - MED Womens', title: 'Womans T-shirt', price: '6000', …}
length: 2
[[Prototype]]: Array(0)

3 Answers 3

1

You're setting the default state of your list to an empty string.

Use

 const [itemList, setItemList] = useState([]);

to set the state to an empty array.

String objects do not have a map function.

Array objects(even empty ones) do have the map function

Also make sure that your response from the server is an array

Sign up to request clarification or add additional context in comments.

4 Comments

I did actually try that but it gives me an empty array now using const [itemList, setItemList] = useState([]);. When I have it set to a string I at least get an array back in console. I understand what you are saying but I get nothing returned in console and nothing showing in the cart list at all with that edit. There's something else up
This shows up in console when i use a string instead of array to declare the useState - (2) [{…}, {…}] 0: {item_key: '698d51a19d8a121ce581499d7b701668', id: 111, name: 'Cuff Beanie', title: 'Cuff Beanie', price: '3000', …} 1: {item_key: '7ce9004ae3ad190443d43d7f81241060', id: 107, name: 'Womans T-shirt - MED Womens', title: 'Womans T-shirt', price: '6000', …} length: 2 [[Prototype]]: Array(0)
You are calling a promise on an await async function, check what the return value is rather than the promise. I.e. const results = await CoCart.get("cart?cart_key=" + value);console.log(results); You will still need to set the useState as [] for the first render
Thankyou for the replies mate. I realised I was going about populating what was in the shopping cart completely the wrong way. I ended up restructuring it completely.
0

In your code you are defining the value of const [itemList, setItemList] = useState(''); as an empty string and map is an array method so insted of an empty string you can use an empty array.

const [itemList, setItemList] = useState([]);

2 Comments

Ok but when I have it set to a string I get an array back in console. I get what you are saying though and I changed the declaration to be an array as you suggested, but now I get nothing returned in console, nothing showing in the cart list at all. If I set it as a string I get the array in console
This shows up in console when i use a string instead of array to declare the useState - (2) [{…}, {…}] 0: {item_key: '698d51a19d8a121ce581499d7b701668', id: 111, name: 'Cuff Beanie', title: 'Cuff Beanie', price: '3000', …} 1: {item_key: '7ce9004ae3ad190443d43d7f81241060', id: 107, name: 'Womans T-shirt - MED Womens', title: 'Womans T-shirt', price: '6000', …} length: 2 [[Prototype]]: Array(0)
0

I was going about trying to populate the contents of a users shopping cart the wrong way, for example I didn't even need useEffect. So I restructured it completely and ended up with this -

import React, {useState} from 'react';
import Modal from 'react-bootstrap/Modal';
import CoCartAPI from "@cocart/cocart-rest-api";
import localforage from "localforage";
import 'bootstrap-icons/font/bootstrap-icons.css';

const wordpressurl = "http://localhost/wordpress/";
const CoCart = new CoCartAPI({
  url: wordpressurl,
});

function Example(props) {
  const [show, setShow] = useState(false);
  const [itemList, setItemList] = useState([]);
  const [cartKey, setCartKey] = useState('');
  const [cartTotal, setCartTotal] = useState('');
  const handleClose = () => setShow(false);

  const url = wordpressurl + "checkout/";

  async function getItems() {
    setShow(true);
    const value = await localforage.getItem('cart_key');
    setCartKey(value);
    await CoCart.get("cart?cart_key=" + value).then((response) => {
      var carttotal = response.data.totals.subtotal / 100;
      const result = response.data.items;
      setItemList(result);
      setCartTotal(carttotal);
    })
  }

  return (
    <>
      <div onClick={() => getItems()} className='cartlable'>Cart</div><div id="cartcount"><div className="cartcount">0</div></div>
      <Modal show={show} onHide={handleClose}>
        <Modal.Header closeButton className="me-2">
          <Modal.Title>Your Cart</Modal.Title>
        </Modal.Header>
        <Modal.Body id="cartlist">
          <div className="container-fluid">
            <div className="row">
              <div className="col-8 text-start"><h5>ITEM</h5></div>
              <div className="col-1 text-center"><h5>QTY</h5></div>
              <div className="col-2 text-end"><h5>SUBTOTAL</h5></div>
              <div className="col-1 text-end pe-2"></div>
            </div>
            {itemList.map(({ id, featured_image, name, value, quantity, totals, item_key }) => (
              <div key={id} className="row align-middle cartitemrows">
                <div className="col-1 text-start"><img src={featured_image} className="cartimage" alt="" /></div>
                <div className="col-7 text-start">{name}</div>
                <div className="col-1 text-center">{quantity.value}</div>
                <div className="col-2 text-end">{totals.total}</div>
                <div className="col-1 text-end pe-2"><i className="bi bi-trash" onClick={() => removeProduct(item_key, value)}></i></div>
              </div>
            ))}
            <div className="row pt-3"><div className="col-11 text-end"><h5>TOTAL : <span id="carttotal">{cartTotal}</span></h5></div></div>
            <form id="form-id" action={url} method="get" encType="multipart/form-data">
              <input type="hidden" name="cocart-load-cart" value={cartKey} />
              <button id="your-id">Checkout</button>
            </form>
          </div>
        </Modal.Body>
        <Modal.Footer>
        </Modal.Footer>
      </Modal>
    </>
  );
}

async function removeProduct(productkey) {
  await CoCart.delete('cart/item/<' + productkey + '>')
    .then((response) => {
      console.log("Response Status:", response.status);
      console.log("Response Headers:", response.headers);
      console.log("Response Data:", response.data);
    });
}
export default Example

No doubt there could be a few improvements that could be made but as is it works perfectly

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.