next.js 如何在点击的特定按钮中添加加载程序

a6b3iqyw  于 2023-08-04  发布在  其他
关注(0)|答案(2)|浏览(88)

我正在创建一个电子商务网站website,我需要创建一个按钮,用户可以点击和产品添加到购物车。
但是在将产品添加到购物车之前,我需要在按钮内显示加载器,以便用户可以等待他们的产品添加到购物车。
问题是所有的按钮都会进入加载状态,而不是只有点击的按钮:


的数据
正如你所看到的,在上面的图片中,所有的加载器都被显示出来了,这不是我的方法。
我的代码:

"use client";

const Products = () => {
  const oval = (
    // This is loader...
  );
  const dispatch = useDispatch();
  const [products, setProducts] = useState<IProducts>();
  const [loader, setLoader] = useState<JSX.Element | string>("ADD TO CART");

  useLayoutEffect(() => {
  // return products...
  }, []);

  const addToDatabase = async (product: IProducts, productId: string) => {
    setLoader(oval);
    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);
    }
  };
  return (
    <>
      <div className="container">
        <div className="">
          {products &&
            products.map((product: IProducts) => (
              <div
                key={product.id}
                className=""
              >
                <Image
                  src={product.image}
                  width={100}
                  height={100}
                  alt={product.title}
                />
                <h1 className="">{product.title}</h1>
                <p className="">${product.price}</p>
                <button
                  id={`product-${product.id}`}
                  className=""
                  onClick={() =>
                    addToDatabase(product, `product-${product.id}`)
                  }
                >
                  <span>{loader}</span>
                </button>
              </div>
            ))}
        </div>
      </div>
    </>
  );
};

export default Products;

字符串
我只需要显示加载器上的特定按钮,而不是所有的按钮。

b5buobof

b5buobof1#

所有按钮都切换到加载状态,因为它们都指向相同的状态。你可以稍微改变一下你的逻辑,使用一个loadingProductId状态,如下所示:

const [loadingProductId, setLoadingProductId] = useState<string>("");
const addToDatabase = async (product: IProducts) => {
  setLoadingProductId(product.id);
  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 {
    setLoadingProductId("");
  }
};

个字符

qacovj5a

qacovj5a2#

我想有两种方法可以处理这个问题,一种是创建一个单独的组件来Map卡,这样每个卡都有自己的加载器状态

const ParentComponent = () => {
const list = ['list of products goes here'];

return <div>
/// other content
list.map(child => <ChildComponent data={child} />)

</div>
}

const ChildComponent = ({data}) => {

const [isLoading, setIsLoading] = useState(false);
async function addItemToCart() {
setIsLoading(true);
try{
// await logic here
}
catch(e) {
// logic here
}
setIsLoading(false)
}
return <div>
// content here
<button loading={isLoading} onClick={addItemToCard} />
</div>
}

字符串
另一种方法是创建一个当前正在添加的项的列表,这样,您的组件就不会有加载程序的true或false状态,而是有一个数组状态

const Component = () => {
// other stuff
const [loadingList, setLoadingList] = useState([]);

function addItemToCart(item) {
if(loadingList.includes(item.id)) return;
setLoadingList([...loadingList, item.id])
// async logic here
setLoadingList(oldState => {
const newState = [...oldState];
const index = newState.indexOf(item.id);
if(index > -1) {
newState.splice(index, 1);
}
return newState
})
}
return <div>

// where button is
<button onClick={() => addItemToCart(item)} 
loading={loadingList.includes(item.id)}
/>

</div>
}

相关问题