javascript - ReactJS 函数与 toFixed 不一致

标签 javascript reactjs function tofixed

当调用 HandlePayNow 函数时,它会执行所有预期的功能,但随后会导致系统崩溃。它将订单数据发送到 API,API 记录它并返回一条成功消息,该函数获取此成功消息,它显示带有正确数字的“请显示付款”警报(与单击按钮时提交的数字相匹配)日志中存在的内容),然后崩溃并提供错误消息:


Cannot read properties of undefined (reading 'toFixed')
TypeError: Cannot read properties of undefined (reading 'toFixed')
at http://localhost:3000/static/js/bundle.js:783:58
at Array.map (\<anonymous\>)
at App (http://localhost:3000/static.js.bundle.js:768:32)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:22965:22)
at updateFunctionComponent (http://localhost:3000/static/js/buindle.js:27559:20)
at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:12557:18)
at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:12601:20)
at invokeGuardedcallback (http://localhost:3000/static/js/bundle.js:12658:35)
at beginWork$1 (http://localhost:3000/static/js/bundle.js:32532:11)

在修改CalculateRunningTotal 函数之前,这种情况不会发生。我大约 99% 确信(当我获得令人惊叹的 StackOverflow 社区的帮助时,情况总是如此),这只是一个愚蠢的例子,我公然忽视了一些非常明显的事情。我的直觉告诉我这与异步中重置小计状态的方式有关,但坦率地说,我在 JS 方面很糟糕。这不是我的包。如果有人能解释我的愚蠢,我将不胜感激。

所有相关功能:


const logToConsole = (message) => {
    setConsoleLogs((prevLogs) => [...prevLogs, message]);
  };

  useEffect(() => {
    const customConsoleLog = console.log;

    console.log = (message) => logToConsole(message);

    return () => {
      console.log = customConsoleLog;
    };
  }, []);

  const calculateItemTotal = (item) => {
    let sizePrice = getSizePrice(item.size);
    let flavorPrice = item.flavors.length * 0.89;

    return sizePrice + flavorPrice + item.toppingsPrice;
  };

  const calculateRunningTotal = () => {
    let total = 0;
  
    for (const itemTotal of runningTotals) {
      total += itemTotal;
    }
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        total *= discountMultiplier;
      }
    }
  
    // Check if total is NaN before applying toFixed
    return isNaN(total) ? 0 : total.toFixed(2);
  };   

  const handleAddToOrder = () => {
    if (!selectedSize) {
      alert("Select a Size!");
      return;
    }
  
    const item = {
      size: selectedSize,
      flavors: selectedFlavors,
      toppingsPrice: toppingsPrice,
    };
  
    setOrderItems((prevItems) => [...prevItems, item]);
    setSubtotal((prevSubtotal) => prevSubtotal + calculateItemTotal(item));
    setRunningTotals((prevTotals) => [...prevTotals, calculateItemTotal(item)]);
  
    setSelectedSize(null);
    setSelectedFlavors([]);
    setToppingsPrice(0);
    setSyrupToppings((prevToppings) =>
      prevToppings.map((topping) => ({
        ...topping,
        isActive: false,
      }))
    );
  };  

  const getSizePrice = (size) => {
    switch (size) {
      case 'Small':
        return 2.49;
      case 'Medium':
        return 3.29;
      case 'Large':
        return 4.19;
      default:
        return 0;
    }
  };

  const handleAddTopping = (price) => {
    setToppingsPrice((prevPrice) => prevPrice + price);
  };

  const calculateCurrentItem = () => {
    let sizePrice = selectedSize ? getSizePrice(selectedSize) : 0;
    let flavorPrice = selectedFlavors.length * 0.89;
    let total = sizePrice + flavorPrice + toppingsPrice;
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        total *= discountMultiplier;
      }
    }
  
    return total.toFixed(2);
  };

  const handleRemoveOrder = (index) => {
  const removedItem = orderItems[index];
  const removedItemTotal = calculateItemTotal(removedItem);

  setOrderItems((prevItems) => prevItems.filter((_, i) => i !== index));
  setRunningTotals((prevTotals) => prevTotals.filter((_, i) => i !== index));

  setSubtotal((prevSubtotal) => {
    const newSubtotal = prevSubtotal - removedItemTotal;
    return newSubtotal < 0 ? 0 : newSubtotal;
  });
};

  const handlePayNow = async () => {
    if (orderItems.length === 0) {
      alert("No items in the order!"); // Make user select more than 0 items
      return;
    }
  
    let name = prompt("Enter customer name:"); // Prompt for customer name
  
    while (!name) {
      name = prompt("Enter customer name:"); // Re-prompt for customer name
    }
  
    setCustomerName(name); // Set the customer name
    
    // Reset the subtotal
    setSubtotal(0);
  
    let originalTotal = subtotal;
    let discountAmount = 0;
    let discountType = "None"; // Default value for discount type
  
    if (selectedDiscount) {
      const discount = discounts.find((discount) => discount.name === selectedDiscount);
      if (discount) {
        const discountMultiplier = 1 - discount.discount;
        discountAmount = originalTotal - (originalTotal * discountMultiplier);
        originalTotal = originalTotal * discountMultiplier;
        discountType = discount.name; // Store the discount type
      }
    }
  
    const logs = [];
    logs.push('');
    logs.push('');
    logs.push(`Size: ${selectedSize ? selectedSize.charAt(0).toUpperCase() + selectedSize.slice(1) : null}`);
  
    const flavorsText = selectedFlavors.length > 0 ? selectedFlavors.join(", ") : "None";
    logs.push(`Flavors: ${flavorsText}`);
  
    const nonCustomAddIns = syrupToppings.filter((topping) => topping.isActive && !topping.custom);
    const selectedAddIns = nonCustomAddIns.map((topping) => topping.name);
  
    if (selectedAddIns.length > 0) {
      logs.push(`Add-ins: ${selectedAddIns.join(", ")}`);
    } else {
      logs.push("Add-ins: None");
    }
  
    const tax = (originalTotal * 0.056).toFixed(2);
    const totalWithTax = (parseFloat(originalTotal) + parseFloat(tax)).toFixed(2);
  
    logs.push('');
    logs.push(`Subtotal: $${originalTotal.toFixed(2)}`);
    logs.push(`Tax: $${tax}`);
    logs.push(`Total: $${totalWithTax}`);
    logs.push('');
  
    setConsoleLogs(logs); // Update the console logs with the new order information
  
    const updatedToppings = syrupToppings.map((topping) => {
      const updatedTopping = { ...topping };
      if (updatedTopping.isActive) {
        updatedTopping.soldCount += 1;
      }
      updatedTopping.isActive = false;
      return updatedTopping;
    });
  
    setSyrupToppings(updatedToppings);
    setSelectedSize(null); // Reset selectedSize to null
    setSelectedFlavors([]); // Reset selectedFlavors to an empty array
    setToppingsPrice(0); // Reset toppingsPrice to 0
    setSelectedDiscount(null); // Reset selectedDiscount to null
    setRunningTotals([]); // Reset the running total
  
    const soldLogs = syrupToppings
      .filter((topping) => topping.isActive && !topping.custom)
      .map((topping) => {
        return {
          name: topping.name,
          price: topping.price,
          isActive: topping.isActive,
          soldCount: topping.soldCount + 1
        };
      });
  
    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(soldLogs)
    };
  
    try {
      const response = await fetch('http://localhost:5000/inventory', requestOptions);
      if (response.ok) {
        // Sold logs successfully updated in the inventory
        console.log('Sold logs updated in the inventory.');
      } else {
        console.error('Failed to update sold logs in the inventory.');
      }
    } catch (error) {
      console.error('Error occurred while updating sold logs in the inventory:', error);
    }
  
    // Send the relevant information to the simulated payment API
    const paymentData = {
      subtotal: originalTotal.toFixed(2),
      tax: tax,
      total: totalWithTax,
      discount: selectedDiscount ? true : false,
      discountAmount: discountAmount.toFixed(2),
      discountType: discountType,
      employee: loginNumberTracking,
    };
  
    try {
      const paymentResponse = await fetch('http://localhost:5000/pay', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(paymentData)
      });
  
      if (paymentResponse.ok) {
        const paymentResult = await paymentResponse.text();
        console.log('Payment API response:', paymentResult);
        if (!selectedDiscount) {
          alert(`Please Present Payment\nSubtotal: ${originalTotal.toFixed(2)}\nTax: ${tax}\nTotal: ${totalWithTax}`);
        } else {
          alert(`Please Present Payment\nSubtotal: $${originalTotal.toFixed(2)}\nDiscount Amount: $${discountAmount.toFixed(2)}\nDiscount Type: ${discountType}\nTax: $${tax}\nTotal (after discount and tax): $${(originalTotal + parseFloat(tax)).toFixed(2)}`);
        }
      } else {
        console.error('Failed to send payment data to the API.');
      }
    } catch (error) {
      console.error('Error occurred while sending payment data to the API:', error);
    }
  };     

  const handleSelectDiscount = (discount) => {
    if (selectedDiscount === discount) {
      setSelectedDiscount(null); // Deselect the currently selected discount
    } else {
      setSelectedDiscount(discount); // Select the clicked discount
    }
  };

一般来说,StackOverflow 对我来说是最后的手段。如果我在这里的话,我至少已经呆了好几个小时了。我需要一个比我懂得更多的人;我的知识不足以解决这个问题。

最佳答案

正如错误消息所示:

Cannot read properties of undefined (reading 'toFixed')

发生错误是因为您尝试调用 toFixed() undefined的方法变量。

根据您提供的信息,很难正确判断是哪个部分导致了问题,但它可能是从 subtotal 发生的。没有被初始化和使用。

这些行:

    // Reset the subtotal
    setSubtotal(0);
  
    let originalTotal = subtotal;

React 状态 setter 是异步的,因此如果您的小计是 undefined当你运行setSubtotal(0)时,仍然是undefined运行后,直到下一个刻度之后,这意味着 originalTotal也将是undefined从而通过调用 originalTotal.toFixed(2) 导致错误.

如果不是这种情况,则可能是其他语句导致的。

关于javascript - ReactJS 函数与 toFixed 不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76715631/

相关文章:

reactjs - 使用 react 路由器在路线上 react 设置状态/属性

reactjs - 使用 redux-form 在多个不同的挂载点绑定(bind)表单

function - 将列表的元素作为参数传递给具有可变参数的函数

javascript - 如何避免重复的元标记?

javascript - Html2Canvas 无法捕获图像

javascript - 无法识别带有(一个空格)的数据目标标签

excel - VBA 自函数返回#VALUE!单元格出错,而在函数窗口中正确返回实际值

javascript - document.getElementById().value 不覆盖现有值

javascript - 在reactjs中通过不同的id从api获取数据

python - 列表理解中的调用函数