React组件传值异常:点击卡片详情始终显示数组最后一项
问题修复方案
核心问题分析
你当前的代码在electronics.map循环里为每个卡片都渲染了一个ShowDetails组件,所有弹窗共用同一个modalShow状态。当点击任意卡片的按钮时,所有弹窗都会被触发显示,而DOM中最后一个弹窗会覆盖前面的,所以始终看到数组最后一项的内容。
修改后的代码
Electronic卡片组件
import { useState } from "react"; import { Button } from "react-bootstrap"; import { Card } from "react-bootstrap"; import { useSelector } from "react-redux"; import ShowDetails from "./ShowDetails"; export default function Electronic() { const electronics = useSelector((state) => state.productReducer); const [modalShow, setModalShow] = useState(false); // 新增状态存储当前选中的商品 const [selectedProduct, setSelectedProduct] = useState(null); return ( <> <center dir="rtl"> <br></br> <br></br> <br></br> <br></br> {electronics.map((item) => ( <Card key={item.id} // 添加唯一key,避免React渲染警告 style={{ width: "18rem", display: "inline-block", backgroundColor: "white", textAlign: "center", borderColor: "#fade0f", margin: 5, }} > <Card.Img variant="top" src={item.product_image} style={{ width: 100, height: 100 }} /> <Card.Body> <Card.Title dir="rtl">{item.name}</Card.Title> <Button style={{ backgroundColor: "#fade0f", borderColor: "#fade0f", color: "black" }} variant="primary" onClick={() => { // 点击时选中当前商品并打开弹窗 setSelectedProduct(item); setModalShow(true); }} > פרטים </Button> </Card.Body> </Card> ))} <br></br> <br></br> <br></br> <br></br> </center> {/* 将弹窗移到循环外,只渲染一个实例 */} <ShowDetails products={selectedProduct} show={modalShow} onHide={() => { setModalShow(false); // 关闭弹窗时清空选中的商品 setSelectedProduct(null); }} /> </> ); }
ShowDetails详情弹窗组件
import { useState } from "react"; import { Image } from "react-bootstrap"; import Button from "react-bootstrap/Button"; import Modal from "react-bootstrap/Modal"; export default function ShowDetails(props) { const [amount, setAmount] = useState(1); // 无选中商品时不渲染弹窗 if (!props.products) return null; return ( <> <Modal {...props} size="sm" aria-labelledby="contained-modal-title-vcenter" centered style={{ textAlign: "center" }} animation={true} > <Modal.Header closeButton></Modal.Header> <Modal.Body dir="rtl"> <Image variant="top" src={props.products.product_image} style={{ width: 200, height: 200 }} /> <Modal.Title id="contained-modal-title-vcenter" style={{ textAlign: "center" }}> {props.products.name} </Modal.Title> <h5>{props.products.description}</h5> <h4>{props.products.price * amount} ₪</h4> <Button style={{ backgroundColor: "#fade0f", borderColor: "#fade0f", color: "black" }} onClick={() => { setAmount(Math.max(1, amount - 1)); }} > - </Button> <h4 style={{ display: "inline-block", margin: 10 }}>{amount}</h4> <Button style={{ backgroundColor: "#fade0f", borderColor: "#fade0f", color: "black" }} onClick={() => { setAmount(Math.min(props.products.qty, amount + 1)); }} > + </Button> <br></br> <br></br> <Button style={{ backgroundColor: "#fade0f", borderColor: "#fade0f", color: "black", width: 200, }} onClick={() => { setAmount(1); }} > הוספה לסל </Button> </Modal.Body> </Modal> </> ); }
关键修改点
- 移除循环内的
ShowDetails组件,改为在循环外仅渲染一个弹窗实例,避免重复创建弹窗导致的覆盖问题。 - 新增
selectedProduct状态存储当前点击的商品,确保弹窗渲染对应的数据。 - 点击按钮时同时设置选中商品和弹窗显示状态,关闭弹窗时清空选中状态。
- 为循环中的
Card添加唯一key,符合React列表渲染规范。
内容的提问来源于stack exchange,提问作者abcdefg
相关产品推荐
相关产品推荐

