我创建了这个网站的前端克隆,一切都很顺利,但是当我到达购物车部分时,我发现有很多工作要做。简而言之,我只是为我的网站创建一个“添加到购物车”按钮,然后当用户单击放入购物车的商品时。在购物车中,我想创建一个编辑功能,用户可以在其中选择他/她的衣服尺寸,为此我创建一个模式(使用 Frammer-Motion),当用户单击“添加到购物车”按钮时,该模式将显示,但每次我单击“编辑”时按钮,模式打开时显示相同的数据(这是购物车中的最后一个项目),当我单击 sizeOption(即 M、L、XL)时,它会更新相同的项目(这是最后一个项目)
import { BiEdit, BiMinusCircle, BiPlusCircle } from "react-icons/bi"
import { BsCartX } from "react-icons/bs"
import { MdDeleteOutline } from "react-icons/md"
import { Link } from "react-router-dom"
import { cartState } from "../recoilState"
import { useRecoilState } from "recoil"
import toast, { Toaster } from 'react-hot-toast';
import NewModal from '../../components/NewModal'
import { useState } from "react"
import { AnimatePresence} from "framer-motion"
const notify = () =\> toast.error('Item Removed From Cart')
const Cart = () =\> {
const [cart, setCart] = useRecoilState(cartState)
const [modalOpen, setModalOpen] = useState(false)
const close = () => setModalOpen(false)
const open = () => setModalOpen(true)
const handleEdit = (selectedSize: any, id: string) => {
setCart((prevCart) => {
return prevCart.map((item) => {
console.log('Checking Item', item.productId)
if (item.productId === id) {
console.log('updating Item', item.productId)
return {
...item,
selectedSize: selectedSize,
}
} else {
return item
}
});
});
};
const handleQuantityChange = (id: string, action: string) => {
setCart((prevCart) => {
return prevCart.map((item) => {
if (item.productId === id) {
if (action === 'increment') {
return { ...item, quantityInCart: item.quantityInCart + 1 };
} else if (action === 'decrement' && item.quantityInCart > 1) {
return { ...item, quantityInCart: item.quantityInCart - 1 };
}
}
return item;
});
});
};
const removeItem = (id: string) => {
setCart((prevCart) => prevCart.filter((item) => item.productId !== id));
};
return (
<div className="p-40">
{cart.length === 0
?
(
<div className='flex flex-col items-center gap-y-44 '>
<h1 className='font-bold text-xl'>SHOPPING CART</h1>
<div className="flex flex-col items-center w-[800px] text-left gap-y-10">
<BsCartX size={150} />
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur similique voluptatem nisi fugit aperiam quasi veniam temporibus, magni fuga repudiandae.</p>
<Link to={'/'}>
<button className="bg-black p-4 text-lg text-white rounded-lg">Return to Shopping</button>
</Link>
</div>
</div>
)
:
(
<>
<h1 className="text-xl text-center font-semibold mb-10 uppercase">Your Cart</h1>
{cart.map((item, index) => {
return (
<div className="flex gap-x-5 mt-16" key={index}>
<div className="flex flex-col gap-y-10 items-start w-[50%]">
<h2 className="font-semibold uppercase ">
Product
</h2>
<div className="flex gap-x-5 items-center">
<img
src={item.image}
className="rounded-lg w-[100px]"
/>
<div className="flex flex-col justify-between">
<div className="text-sm flex flex-col gap-y-2">
<h4 className="font-semibold">{item.name}</h4>
<p className="">Category: {item.category}</p>
<p>Size: {item.selectedSize}</p>
</div>
<div className="flex gap-x-2 mt-5">
<BiEdit
size={20}
onClick={open}
className="cursor-pointer"
/>
<MdDeleteOutline
className="cursor-pointer"
size={20}
onClick={() => {
removeItem(item.productId)
notify()
}}
/>
<Toaster />
</div>
</div>
</div>
</div>
<div className="flex flex-col w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Price</h2>
<p>Rs. {item.price}</p>
</div>
<div className="flex flex-col items-center w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Quantity</h2>
<div className="flex gap-x-3 items-center">
<BiPlusCircle size={20} onClick={() => handleQuantityChange(item.productId, 'increment')} />
{item.quantityInCart}
{item.quantityInCart > 1 && <BiMinusCircle size={20} onClick={() => handleQuantityChange(item.productId, 'decrement')} />}
</div>
</div>
<div className="flex flex-col items-end w-[20%] gap-y-24">
<h2 className="font-semibold uppercase ">Total</h2>
<p>Total Price: {item.quantityInCart * item.price}</p>
</div>
<AnimatePresence
initial={false}
mode='wait'
onExitComplete={() => null}
>
{modalOpen && <NewModal modalOpen={modalOpen} handleClose={close} text={item.name} size={item.sizeOptions} id={item.productId} handleEdit={handleEdit} infoModal={false} />}
</AnimatePresence>
</div>
)
})}
<div className="mt-20 text-xl font-semibold">
Total Bill: {cart.reduce((total: any, item: any) => total + item.quantityInCart * item.price, 0)}
</div>
</>
)
}
</div>
)
}
export default Cart
import React from "react";
import { motion } from "framer-motion";
import Backdrop from "./Backdrop";
const dropIn = {
hidden: {
y: "-100vh",
opacity: 0,
},
visible: {
y: "0",
opacity: 1,
transition: {
duration: 0.1,
type: "spring",
damping: 25,
stiffness: 500,
},
},
exit: {
y: "100vh",
opacity: 0,
},
};
const styles: React.CSSProperties = {
width: 'clamp(50%, 700px, 90%)',
borderRadius: '12px',
backgroundColor: '#fff',
}
const Modal = ({ handleClose, text, infoModal, size, id, handleEdit }: any) => {
return (
<Backdrop onClick={handleClose}>
<motion.div
onClick={(e) => e.stopPropagation()}
style={styles}
variants={dropIn}
initial="hidden"
animate="visible"
exit="exit"
>
{infoModal === true ?
(
<div className="flex justify-between items-center p-10">
<p className="text-2xl">{text}</p>
<button onClick={handleClose} className=" bg-orange-600 px-4 py-2 rounded-full" >Close</button>
</div>
)
:
(
<div className="p-10 flex flex-col gap-y-5">
{text}
<div className="flex gap-x-5 items-center">
<p>Size:</p>
{size.map((selectedSize: any, index: any) => {
return (
<motion.div
key={index}
className="border cursor-pointer px-4 py-2 text-lg"
onClick={() => handleEdit(selectedSize, id)}
whileHover={{backgroundColor: "black", color: 'white'}}
whileTap={{backgroundColor: "#707B7C"}}
>
{selectedSize}
</motion.div>
)
})}
</div>
<button onClick={handleClose} className=" bg-orange-600 px-4 py-2 rounded-full" >Close</button>
</div>
)
}
</motion.div>
</Backdrop>
);
};
export default Modal;
我想根据输入在模态上显示数据并相应地在购物车上更新
您使用单个布尔值来确定每个模式是否打开。 因此,当您尝试打开任何记录的模态时,您会为 every 记录打开 all 模态。
不仅仅跟踪all模态是否应该打开,而是跟踪which模态应该打开。 例如,您的
modalOpen
状态值可能是您要为其打开模态框的记录的 productId
。 像这样的东西:
const [modalOpen, setModalOpen] = useState();
最初是
undefined
,因为最初没有打开任何模式。 打开一个记录需要将值设置为该记录的标识符:
onClick={() => setModalOpen(item.productId)}
关闭它需要将其设置回
undefined
:
onClick={() => setModalOpen(undefined)}
(您也可以使用类似
-1
的东西作为不匹配任何记录的魔法值,这取决于您。)
然后,对于每条记录,您将检查状态值是否与该记录的标识符匹配,以查看模式是否应该打开:
{modalOpen === item.productId &&
<NewModal
modalOpen={true}
handleClose={() => setModalOpen(undefined)}
text={item.name}
size={item.sizeOptions}
id={item.productId}
handleEdit={handleEdit}
infoModal={false}
/>
}