0

I am trying to add items to a shopping cart. I have declared cart as an empty array and I am still getting the error:

TypeError: cart.map is not a function ProductContext.js:34
addItemToCart ProductContext.js:34
addItemHandler ProductCard.js:47
onClick ProductCard.js:60

Here is my context:

// ProductContext.js

import React, { createContext, useState } from "react"
import { graphql, useStaticQuery } from "gatsby"

const ProductContext = createContext({
  cart: [],
  addItem: () => {}
})

const Provider = ({ children }) => {
  const [cart, setCart] = useState([]);

  const [productsList] = useState(
    useStaticQuery(
      graphql`
        query SkusForProduct {
          skus: allStripeSku(sort: { fields: [price] }) {
            edges {
              node {
                id
                currency
                price
                attributes {
                  name
                }
              }
            }
          }
        }
      `
    )
  )

  const addItemToCart = skuId => {
    let itemExisted = false
    let updatedCart = cart.map(item => {
      if (skuId === item.sku) {
        itemExisted = true
        return { sku: item.sku, quantity: ++item.quantity }
      } else {
        return item
      }
    })
    if (!itemExisted) {
      updatedCart = [...updatedCart, { sku: skuId, quantity: 1 }]
    }
    setCart({ cart: updatedCart })

    localStorage.setItem('stripe_checkout_items', JSON.stringify(updatedCart))
  }

  return (
    <ProductContext.Provider value={{ skus: productsList.skus, addItem: addItemToCart }}>
      {children}
    </ProductContext.Provider>
  )
}

export { ProductContext, Provider }

And my ProductCard

// ProductCard.js    

import React, { useState, useContext } from "react"
import { ProductContext } from "../context/ProductContext"

const cardStyles = {
  display: "flex",
  flexDirection: "column",
  justifyContent: "space-around",
  alignItems: "flex-start",
  padding: "1rem",
  marginBottom: "1rem",
  boxShadow: "5px 5px 25px 0 rgba(46,61,73,.2)",
  backgroundColor: "#fff",
  borderRadius: "6px",
  maxWidth: "300px",
}
const buttonStyles = {
  fontSize: "13px",
  textAlign: "center",
  color: "#fff",
  outline: "none",
  padding: "12px",
  boxShadow: "2px 5px 10px rgba(0,0,0,.1)",
  backgroundColor: "rgb(255, 178, 56)",
  borderRadius: "6px",
  letterSpacing: "1.5px",
}

const formatPrice = (amount, currency) => {
  let price = (amount / 100).toFixed(2)
  let numberFormat = new Intl.NumberFormat(["en-US"], {
    style: "currency",
    currency: currency,
    currencyDisplay: "symbol",
  })
  return numberFormat.format(price)
}

const ProductCard = () => {
  const [disabled] = useState(false)
  const [buttonText, setButtonText] = useState("Add to Cart")
  const [paymentMessage, setPaymentMessage] = useState("")

  const skus = useContext(ProductContext).skus
  const addItem = useContext(ProductContext).addItem

  const addItemHandler = (event, skuId, quantity = 1) => {
    addItem(skuId);
  }


  return (
    <div>
      {skus.edges.map(({ node: sku }) => {
        return (
          <div style={cardStyles} key={sku.id}>
            <h4>{sku.attributes.name}</h4>
            <p>Price: {formatPrice(sku.price, sku.currency)}</p>
            <button
              style={buttonStyles}
              onClick={event => addItemHandler(event, sku.id)}
              disabled={disabled}
            >
              {buttonText}
            </button>
            {paymentMessage}
          </div>
        )
      })}
    </div>
  )
}

export default ProductCard

I have logged the output of cart in the addItemToCart function and I get an empty array. Not sure what I've done wrong. Any help would be greatly appreciated!

8
  • well cart is a constant with no value Commented Feb 25, 2020 at 23:45
  • Does cart always stays as an array? In the Provider, right before you do the return, if you console.log(cart) does it ever change to anything else? Commented Feb 25, 2020 at 23:45
  • @RobertRocha it's still an array and the map method should work just fine. It sounds like he's accidentally changing his state to something else other than array. Commented Feb 25, 2020 at 23:47
  • @goto1 strange, seems like it's adding one item at least, I get this array with one item: {…} ​ cart: (1) […] ​​ 0: {…} ​​​ quantity: 1 ​​​ sku: "sku_Gi0Yhgc3z0xz37" But when I try to add another item I get the same error. Am I changing the array to an object somehow? Commented Feb 25, 2020 at 23:49
  • If you console.log(updatedCart) right before setCart({ cart: updatedCart }), is updatedCart always an array? Commented Feb 25, 2020 at 23:51

1 Answer 1

1

Here is the problem line of code:

setCart({ cart: updatedCart })

After that runs, cart will no longer be an array (it will be an object with the property "cart", which is an array) and therefore not have a map function.

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

3 Comments

Yes that was it! Thank you!
Glad I could help.
which is NOT an array? :)

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.