You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js修改组件列表后旧组件值变为undefined问题求助

React表格总价计算Bug修复:多行时旧项值变为undefined

我遇到一个困扰了一周的Bug:在React表格中,每行对应一个产品列表项。当修改数量或价格时,最后一列的总价会更新并同步到待提交后端的列表中。控制台打印newList显示最后一项总价可正常添加到列表,但当列表项超过2个时,之前的旧项值会变为undefined。

原组件代码:

function CountTotalPrice({
  data,
  setListProductImport,
  listProductImport,
  setNewList,
}) {
  const [price, setPrice] = useState<any>()
  const handleSetPrice = () => {
    const list = listProductImport
    const newList = list.map((item) => {
      if (item.productId == data.productId) {
        const totalPrice = new BigNumber(item.amount).multipliedBy(
          item.costPrice,
        )
        const discountPrice = new BigNumber(item.amount)
          .multipliedBy(item.costPrice)
          .multipliedBy(item.discount)
          .dividedBy(100)
        if (item.discount) {
          const afterPrice = totalPrice.minus(discountPrice)
          setPrice(afterPrice)
        } else {
          setPrice(totalPrice)
        }
      }
      return item
    })
  }

  useEffect(() => {
    handleSetPrice()
  }, [listProductImport])

  useEffect(() => {
    if (price) {
      const list = listProductImport
      const newList = list.map((item) => {
        if (item.productId === data.productId) {
          return { ...item, price: price.toFixed() }
        }
        return item
      })
      console.log("newList", newList)

      setNewList(newList)
    }
  }, [price])

  return (
    <div className="py-2 text-center text-white rounded-md cursor-pointer bg-successBtn">
      {new BigNumber(price).toFormat(0)} đ
    </div>
  )
}

问题分析与修复

核心问题

  • 多实例状态冲突:每个CountTotalPrice组件都维护独立的price状态,当列表项超过2个时,未被更新的组件实例中price仍为undefined,渲染时触发错误导致旧项值异常。
  • 冗余状态中转:通过price状态间接更新列表的逻辑,会导致多轮状态更新,引发数据同步不一致。
  • 缺乏空值防护:未处理price为undefined时的渲染逻辑,直接调用new BigNumber(price)会抛出错误。

修复后的代码

function CountTotalPrice({
  data,
  listProductImport,
  setNewList,
}) {
  // 直接计算当前行的总价,无需组件内部状态维护
  const getTotalPrice = () => {
    const currentItem = listProductImport.find(item => item.productId === data.productId);
    if (!currentItem) return new BigNumber(0);

    let total = new BigNumber(currentItem.amount).multipliedBy(currentItem.costPrice);
    if (currentItem.discount) {
      const discount = total.multipliedBy(currentItem.discount).dividedBy(100);
      total = total.minus(discount);
    }
    return total;
  };

  const totalPrice = getTotalPrice();

  // 直接根据计算结果更新列表,去掉冗余状态中转
  useEffect(() => {
    const updatedList = listProductImport.map(item => 
      item.productId === data.productId 
        ? { ...item, price: totalPrice.toFixed() } 
        : item
    );
    setNewList(updatedList);
  }, [listProductImport, totalPrice, setNewList, data.productId]);

  return (
    <div className="py-2 text-center text-white rounded-md cursor-pointer bg-successBtn">
      {totalPrice.toFormat(0)} đ
    </div>
  );
}

修复要点

  1. 移除内部price状态:直接通过函数计算当前行总价,避免多组件实例间的状态干扰。
  2. 简化更新逻辑:在useEffect中直接用计算结果更新列表,减少不必要的状态流转。
  3. 增加空值判断:通过find确保找到当前行数据,兜底返回0避免计算错误。
  4. 明确依赖数组:完善useEffect的依赖项,确保更新时机准确。

内容的提问来源于stack exchange,提问作者Mohtep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 20:47:13