如何在同一组件中多次使用带不同参数的RTK Query函数?
解决RTK Query购物车计数器共享加载状态问题
问题根源
你当前的代码中,所有购物车商品共用同一个useAddCartMutation和useRemoveCartMutation实例,导致它们的isLoading状态全局共享——点击任意一个商品的加减按钮,所有按钮都会显示加载状态。
你之前尝试在map循环内调用mutation hook的做法,违反了React Hooks核心规则:Hooks必须在组件顶层作用域调用,不能在循环、条件或嵌套函数中调用,因此触发了TypeScript错误。
解决方案
通过在父组件维护一个状态,单独跟踪每个商品ID对应的加减操作加载状态,再将对应状态传递给每个QCounter组件,实现单个按钮的加载状态独立控制。
修改Cart组件代码
import { useState } from 'react'; // 导入你的类型定义和RTK Query hooks const Cart = () => { const { isLoading: cartLoading, isSuccess, data: cart, } = useGetCartQuery({ userId: userData.id }); const [addItem] = useAddCartMutation(); const [removeItem] = useRemoveCartMutation(); // 维护每个商品的加载状态:key为productId,value存add/remove的加载状态 const [itemLoadingStates, setItemLoadingStates] = useState<Record<string, { add: boolean; remove: boolean }>>({}); const handleAddBtn = async (item: cartItemType) => { if (item.product.availability <= item.quantity) { throw new Error("库存不足,无法增加数量"); } const productId = item.product.id as string; // 设置当前商品的添加按钮为加载中 setItemLoadingStates(prev => ({ ...prev, [productId]: { ...prev[productId], add: true } })); try { // 调用mutation并等待请求完成 await addItem({ userId: userData.id as string, productId, quantity: 1, }).unwrap(); } catch (error) { console.error("添加商品失败:", error); } finally { // 请求结束后,取消加载状态 setItemLoadingStates(prev => ({ ...prev, [productId]: { ...prev[productId], add: false } })); } }; const handleRemoveBtn = async (item: cartItemType, count: number) => { if (item.quantity < count) return; const productId = item.product.id as string; // 设置当前商品的移除按钮为加载中 setItemLoadingStates(prev => ({ ...prev, [productId]: { ...prev[productId], remove: true } })); try { await removeItem({ userId: userData.id as string, productId, count, }).unwrap(); } catch (error) { console.error("移除商品失败:", error); } finally { setItemLoadingStates(prev => ({ ...prev, [productId]: { ...prev[productId], remove: false } })); } }; if (cartLoading) return <div>加载购物车中...</div>; if (!isSuccess || !cart) return <div>购物车为空</div>; return ( <div> {cart.items.map((item: cartItemType) => { const productId = item.product.id as string; // 获取当前商品的加载状态,默认都为false const { add: isAddLoading, remove: isRemoveLoading } = itemLoadingStates[productId] || { add: false, remove: false }; return ( <QCounter key={productId} availability={item.product.availability} count={item.quantity} handleAddBtn={() => handleAddBtn(item)} handleRemoveBtn={() => handleRemoveBtn(item, 1)} AddBtnLoading={isAddLoading} RemoveBtnLoading={isRemoveLoading} height="36px" width="36px" /> ); })} </div> ); };
QCounter组件无需修改
你的QCounter组件逻辑正确,只要接收正确的单个商品加载状态即可正常工作。
原理说明
- 通过
useState创建对象状态,以商品ID为键,存储每个商品的加减操作加载状态。 - 在调用mutation前后,分别更新对应商品的加载状态:请求开始时设为
true,请求完成(成功/失败)后设为false。 - 渲染每个
QCounter时,根据商品ID取出对应的加载状态传递给组件,实现单个按钮的独立加载状态控制。
内容的提问来源于stack exchange,提问作者HUS.97
相关产品推荐
相关产品推荐

