React JS 中模态数据没有更新

问题描述 投票:0回答:1

我创建了这个网站的前端克隆,一切都很顺利,但是当我到达购物车部分时,我发现有很多工作要做。简而言之,我只是为我的网站创建一个“添加到购物车”按钮,然后当用户单击放入购物车的商品时。在购物车中,我想创建一个编辑功能,用户可以在其中选择他/她的衣服尺寸,为此我创建一个模式(使用 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;

我想根据输入在模态上显示数据并相应地在购物车上更新

javascript reactjs typescript modal-dialog simplemodal
1个回答
0
投票

您使用单个布尔值来确定每个模式是否打开。 因此,当您尝试打开任何记录的模态时,您会为 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}
  />
}
© www.soinside.com 2019 - 2024. All rights reserved.