Skip to content Skip to sidebar Skip to footer

Database (firestore) Call Is Only Taking The First Value

I want to make a call the database (firestore) to return the data of the products in real time that the user has added them to the cart then this data will be used in a code to get

Solution 1:

In your onSnapshot handler, you are calling console.log(array) and setItems(array) prematurely. This potentially causes your app to be rendered multiple times. You should make sure to be calling these lines outside of the forEach loop.

.onSnapshot((docs) => {
  let array = []
  docs.forEach(doc => {
    array.push(doc.data())
  });
  console.log(array)
  setItems(array)
});

But even so, it would be more efficient to fetch the item prices before calling setItems. Plus, instead of calling out to the database one-by-one using forEach, you should bundle the requests into batches like shown in this answer which is available as a utility function, fetchDocumentsWithId().

.onSnapshot((docs) => {
  const cartItems = [], itemPriceObject = {};
  // cartItems will be ({ id: string, quantity: number, price: number | null, lineTotal: number })[]// itemPriceObject will be a map of IDs to their price (a Record<string, number | null>) (used to deduplicate IDs & store prices)
  
  docs.forEach(doc => {
    const cartItem = doc.data()
    cartItems.push(cartItem)
    itemPriceObject[cartItem.id] = null
  });
  
  // idsArray is a deduplicated list of IDsconst idsArray = Object.keys(itemPriceObject);
  
  fetchDocumentsWithId(
    db.collection("products"),
    idsArray,
    (itemDoc) => {
      itemPriceObject[itemDoc.id] = itemDoc.get("price") // more efficient than itemDoc.data().price
    }
  )
    .then(() => {
      // if here, all prices (that are available) have been retrieved// MAY BE NULL! Consider these items to be "not available"const totalSum = 0// put prices in their items, calculate line cost and add to total
      cartItems.forEach(item => {
        item.price = itemPriceObject[item.id]
        item.lineTotal = item.price === null ? 0 : item.price * item.quantity
        totalSum += item.lineTotal
      }
      
      // set items & total sumsetItems(cartItems)
      setTotal(totalSum)
    })
    .catch((error) => {
      // failed to retrieve some documents from the database// TODO: update UI
    });
});

Note: For clarity, subTotal (meaning: the sum of some, but not all values) was renamed to lineTotal (meaning: the cost of items in this entry/line, the cost x quantity)

Post a Comment for "Database (firestore) Call Is Only Taking The First Value"