如何为点击的特定按钮添加Loader?电商网站按钮加载问题
解决单个按钮点击后所有按钮显示加载状态的问题
问题根源在于你使用了一个全局的loader状态变量控制所有按钮的显示内容,调用setLoader(oval)时所有按钮会同步切换成加载状态。要实现仅被点击的按钮显示加载效果,需要为每个商品单独维护加载状态,而非使用单个变量。
修改方案
- 将全局
loader状态替换为对象,跟踪每个商品ID的加载状态 - 添加购物车请求时,仅标记当前点击的商品为加载中
- 请求完成后(成功/失败),取消该商品的加载状态
修改后的完整代码
"use client"; const Products = () => { const oval = ( // 你的加载器组件,示例用文字占位 <span className="loader">Loading...</span> ); const dispatch = useDispatch(); const [products, setProducts] = useState<IProducts>(); // 用对象跟踪每个商品的加载状态,键为商品ID,值为是否加载中 const [loadingIds, setLoadingIds] = useState<Record<string, boolean>>({}); useLayoutEffect(() => { // 获取商品列表的逻辑 }, []); const addToDatabase = async (product: IProducts) => { const productId = product.id; // 标记当前商品为加载中 setLoadingIds(prev => ({ ...prev, [productId]: true })); try { const res = await axios.post("/api/cart", { product }); if (res.status === 200) { dispatch(addProduct(product)); } else { alert("Something went wrong"); } } catch (error) { alert("INTERNAL SERVER ERROR"); console.log(error); } finally { // 无论请求结果如何,取消当前商品的加载状态 setLoadingIds(prev => ({ ...prev, [productId]: false })); } }; return ( <> <div className="container"> <div> {products && products.map((product: IProducts) => ( <div key={product.id}> <Image src={product.image} width={100} height={100} alt={product.title} /> <h1>{product.title}</h1> <p>${product.price}</p> <button id={`product-${product.id}`} onClick={() => addToDatabase(product)} {/* 加载时禁用按钮,防止重复点击 */} disabled={loadingIds[product.id]} > {/* 根据当前商品的加载状态显示对应内容 */} {loadingIds[product.id] ? oval : "ADD TO CART"} </button> </div> ))} </div> </div> </> ); }; export default Products;
关键说明
loadingIds对象:通过商品ID作为键,精准控制单个商品按钮的加载状态,避免全局状态干扰finally块:确保请求结束后一定会取消加载状态,防止按钮一直处于加载态disabled属性:可选添加,避免用户在加载过程中重复点击同一按钮,减少无效请求
内容的提问来源于stack exchange,提问作者Kannu Mandora
相关产品推荐
相关产品推荐

