Chakra UI Modal组件遍历对象数组时仅显示首个条目问题
问题原因
你当前的代码中,整个父组件仅初始化了一次useDisclosure,遍历生成的所有Modal和触发按钮都共享同一组开关状态。点击任意按钮触发onOpen后,所有遍历生成的Modal会同时处于打开状态,多个Modal层级叠加在视口上,视觉上你只能看到最上层的那一个,所以会出现永远只展示第一条内容的现象。
解决方案
方案1:抽离独立子组件(更推荐,状态拆分更清晰)
把单个课程的按钮+Modal逻辑抽成独立子组件,每个子组件内部自己维护useDisclosure状态,不同条目的开关状态完全隔离,不会互相干扰:
import { Box, Button, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, useDisclosure } from "@chakra-ui/react"; // 独立课程卡片组件,内部维护自己的弹窗状态 const CourseCard = ({ course }) => { const { isOpen, onOpen, onClose } = useDisclosure(); return ( <Box as="section"> <Button onClick={onOpen} size="sm"> {course.courseTitle} </Button> <Modal isOpen={isOpen} onClose={onClose}> <ModalOverlay /> <ModalContent> <ModalHeader>{course.courseTitle}</ModalHeader> <ModalCloseButton /> <ModalBody>{course.courseContent}</ModalBody> <ModalFooter> <Button colorScheme="blue" mr={3} onClick={onClose}> Close </Button> </ModalFooter> </ModalContent> </Modal> </Box> ) } const courses = [ { courseTitle: "London", courseContent: "Lodon Lorem ipsum, dolor sit amet consectetur adipisicing elit. Tempore deleniti assumenda quas minus, fugiat veniam necessitatibus laborum qui similique dolor!" }, { courseTitle: "Geography", courseContent: "Geography Lorem ipsum, dolor sit amet consectetur adipisicing elit. Tempore deleniti assumenda quas minus, fugiat veniam necessitatibus laborum qui similique dolor!" } ]; export default function () { return ( <Box mt={5} display="flex" gridGap={3}> {courses.map((course, idx) => ( <CourseCard key={idx} course={course} /> ))} </Box> ); }
方案2:父组件维护激活索引
如果不想抽离组件,也可以在父组件存储当前打开的弹窗索引,单独控制对应Modal的显示隐藏:
import { useState } from "react"; import { Box, Button, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay } from "@chakra-ui/react"; const courses = [ { courseTitle: "London", courseContent: "Lodon Lorem ipsum, dolor sit amet consectetur adipisicing elit. Tempore deleniti assumenda quas minus, fugiat veniam necessitatibus laborum qui similique dolor!" }, { courseTitle: "Geography", courseContent: "Geography Lorem ipsum, dolor sit amet consectetur adipisicing elit. Tempore deleniti assumenda quas minus, fugiat veniam necessitatibus laborum qui similique dolor!" } ]; export default function () { // null代表所有弹窗关闭,存储数值对应打开的课程索引 const [openIdx, setOpenIdx] = useState(null); const onClose = () => setOpenIdx(null); return ( <Box mt={5} display="flex" gridGap={3}> {courses.map((course, idx) => ( <Box as="section" key={idx}> <Button onClick={() => setOpenIdx(idx)} size="sm"> {course.courseTitle} </Button> <Modal isOpen={openIdx === idx} onClose={onClose}> <ModalOverlay /> <ModalContent> <ModalHeader>{course.courseTitle}</ModalHeader> <ModalCloseButton /> <ModalBody>{course.courseContent}</ModalBody> <ModalFooter> <Button colorScheme="blue" mr={3} onClick={onClose}> Close </Button> </ModalFooter> </ModalContent> </Modal> </Box> ))} </Box> ); }
内容的提问来源于stack exchange,提问作者AbdulAzeez Olanrewaju
相关产品推荐
相关产品推荐

