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

MERN栈购物车子组件数量变更后,如何同步更新父组件总价?

问题:购物车子组件修改数量后父组件总价未同步更新

购物车父组件包含CartItem子组件,子组件配备商品数量增减按钮。修改数量时,子组件状态与数据库已完成更新,但父容器展示的购物车总价未同步更新。

父组件代码

const Cart = () => {
  const [cartItems, setCartItems] = useState([]);
  const[Total,setTotal] = useState(0)
  const userID = useGetUserID()

  useEffect(() => {
    fetchCartitems(); 
  }, []);
  
  const fetchCartitems = async () => {
      try {
        const response = await axios.get(
          `http://localhost:5174/cart/getcart/${userID}`
        );
        setCartItems(response.data.cartItems);
      } catch (err) {
        console.log(err);
      }
    };
    
  useEffect(() => {
    setTotal(cartItems.reduce((total, item) => {
      return total + item.price * item.quantity;
    },0));
  }, [cartItems]);

  console.log(Total)

  return (
    <div className='container px-10 flex'>
      <div>
      <h2 className='py-6'>My Cart</h2>
      <ul className='space-y-3'>
        {cartItems.map(item => (
          <CartItem key={item.productId} productId={item.productId} title={item.name} price={item.price} quantity={item.quantity} imgs={item.imgs}/>
        ))}
      </ul>
      </div>
      <div>
      {Total}
      </div>
    </div>
  );
}

export default Cart

子组件代码

const CartItem = (props) => {
  const [qty, setqty] = useState(props.quantity)

  const decreaseQuantity = async (productId, quantity) => {
    try {
      const response = await axios.patch("http://localhost:5174/cart/updatecart", {
        productId,
        quantity: qty - 1,
        userID: useGetUserID(),
      });
      
      if(qty > 1){
        setqty(qty => qty - 1)
      }
     
    console.log(response.data);
    } catch (err) {
      console.error(err.response.data);
    }
  }
  
  const increaseQuantity = async (productId, quantity) => {
    try {
      const response = await axios.patch("http://localhost:5174/cart/updatecart", {
        productId,
        quantity: qty + 1,
        userID: useGetUserID(),
      });
      
      if(qty >= 1){
        setqty(qty => qty + 1)
      }
     
    console.log(response.data);
    } catch (err) {
      console.error(err.response.data);
    }
  }

  return (
    <div className='flex space-x-3 font-Inter'>
      <div>
      <img src={props.imgs} alt="" className='w-32 h-32 rounded-md'/>
      </div>
      <div className="flex flex-col justify-between">
      <h1 className='font-bold text-xl'>{props.title}</h1>
        <h1>{props.price}</h1>
        <div className="flex">
        <button className='border border-b-2 px-3 rounded-tl-md rounded-bl-md' onClick={() =>decreaseQuantity(props.productId,props.quantity)}>-</button>
        <h1 className='px-2'>{qty}</h1>
        <button className='border border-b-2 px-3 rounded-tr-md rounded-br-md' onClick={() =>increaseQuantity(props.productId,props.quantity)}>+</button>
        </div>
      </div>  
    </div>
  )
}

export default CartItem

原因分析

父组件的cartItems状态仅在组件挂载时通过fetchCartitems获取一次。子组件修改数量后,父组件的cartItems未更新,导致依赖cartItems计算总价的useEffect不会触发,总价自然无法同步。

解决方案

方案一:子组件修改后通知父组件刷新数据

让子组件在完成数据库更新后,调用父组件传递的刷新函数,重新获取购物车数据:

  1. 父组件新增刷新函数并传递给子组件
const Cart = () => {
  // ... 原有代码不变

  // 添加刷新购物车的函数
  const refreshCart = () => {
    fetchCartitems();
  };

  return (
    <div className='container px-10 flex'>
      <div>
        <h2 className='py-6'>My Cart</h2>
        <ul className='space-y-3'>
          {cartItems.map(item => (
            <CartItem 
              // ... 原有props不变
              refreshCart={refreshCart} // 传递刷新函数
            />
          ))}
        </ul>
      </div>
      <div>{Total}</div>
    </div>
  );
};
  1. 子组件接收并调用刷新函数
const CartItem = (props) => {
  const [qty, setqty] = useState(props.quantity)

  const decreaseQuantity = async (productId) => {
    try {
      if (qty <= 1) return; // 提前拦截无效操作
      const response = await axios.patch("http://localhost:5174/cart/updatecart", {
        productId,
        quantity: qty - 1,
        userID: useGetUserID(),
      });
      setqty(prev => prev - 1);
      props.refreshCart(); // 调用父组件刷新函数
      console.log(response.data);
    } catch (err) {
      console.error(err.response.data);
    }
  }
  
  const increaseQuantity = async (productId) => {
    try {
      const response = await axios.patch("http://localhost:5174/cart/updatecart", {
        productId,
        quantity: qty + 1,
        userID: useGetUserID(),
      });
      setqty(prev => prev + 1);
      props.refreshCart(); // 调用父组件刷新函数
      console.log(response.data);
    } catch (err) {
      console.error(err.response.data);
    }
  }

  // ... 原有return内容不变
};

方案二:父组件统一管理状态(更推荐)

让父组件负责所有购物车数据的状态管理,子组件仅触发操作,避免状态分散导致的不同步:

  1. 父组件新增数量修改函数并传递给子组件
const Cart = () => {
  // ... 原有代码不变

  // 修改商品数量的函数
  const updateQuantity = async (productId, newQty) => {
    try {
      if (newQty < 1) return;
      // 先更新本地状态,提升用户体验
      setCartItems(prev => prev.map(item => 
        item.productId === productId ? {...item, quantity: newQty} : item
      ));
      // 再同步更新数据库
      await axios.patch("http://localhost:5174/cart/updatecart", {
        productId,
        quantity: newQty,
        userID,
      });
    } catch (err) {
      console.error(err.response.data);
      // API失败时回滚状态
      fetchCartitems();
    }
  };

  return (
    <div className='container px-10 flex'>
      <div>
        <h2 className='py-6'>My Cart</h2>
        <ul className='space-y-3'>
          {cartItems.map(item => (
            <CartItem 
              // ... 原有props不变
              updateQuantity={updateQuantity} // 传递修改函数
            />
          ))}
        </ul>
      </div>
      <div>{Total}</div>
    </div>
  );
};
  1. 子组件移除本地状态,直接使用父组件传递的数据
const CartItem = (props) => {
  const decreaseQuantity = () => {
    props.updateQuantity(props.productId, props.quantity - 1);
  };

  const increaseQuantity = () => {
    props.updateQuantity(props.productId, props.quantity + 1);
  };

  return (
    <div className='flex space-x-3 font-Inter'>
      <div>
        <img src={props.imgs} alt="" className='w-32 h-32 rounded-md'/>
      </div>
      <div className="flex flex-col justify-between">
        <h1 className='font-bold text-xl'>{props.title}</h1>
        <h1>{props.price}</h1>
        <div className="flex">
          <button className='border border-b-2 px-3 rounded-tl-md rounded-bl-md' onClick={decreaseQuantity}>-</button>
          <h1 className='px-2'>{props.quantity}</h1>
          <button className='border border-b-2 px-3 rounded-tr-md rounded-br-md' onClick={increaseQuantity}>+</button>
        </div>
      </div>  
    </div>
  )
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:15:01