All modals opening at once when mapping over an array of objects in a React

Viewed 26

I'm still fairly new to React and I'm wondering how I go about ensuring that each card shows the correct data in the modal? Right now it is displaying all the modals at once and only displaying the last one.

I've added my updated code below but help on fixing this problem would be greatly appreciated!

// import projects into portfolio
import React, { useState } from 'react';

// react bootstrap imports
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';


const projectData = [
    {
        id: 1,
        name: 'Project 1',
        photo: project1,
        url: 'https://',
        gitHub: 'https://',
        summary: 'Lorem ipsum',
        techSkills: 'abc'
    },
    {
        id: 2,
        name: 'Project 2',
        photo: project2,
        url: 'https://',
        gitHub: 'https://',
        summary: 'Lorem ipsum',
        techSkills: 'abc'
    },
    {
        id: 3,
        name: 'Project 3',
        url: 'https://',
        photo: project3,
        gitHub: 'https://',
        summary: 'Lorem ipsum',
        techSkills: 'abc'
    },
    {
        id: 4,
        name: 'Project 4',
        url: 'https://',
        photo: project4,
        gitHub: 'https://',
        summary: 'lorem ipsum',
        techSkills: 'abc'
    }
];

function Project(props) {


    // useState variables to display modals
    const [showModal, setShowModal] = useState(false);
    const handleClose = () => setShowModal(false);
    const handleShow = () => setShowModal(true);

    return (
        <div className='container'>
            <div className='row'>
                {projectData.map((data) => {
                    return (
                        <div className='col-3 d-flex mb-4' key={data.id}>
                            <Button onClick={handleShow} className="project-card card p-0 border-5 border-dark shadow-lg">
                                <img className='card-img shadow-lg' src={data.photo} alt={data.name} >
                                </img>
                            </Button>


                        </div>
                    );
                })}
                {projectData.map(({id, name, summary, techSkills, url, gitHub}) => {
                    return (
                        <Modal
                            {...props}
                            size="lg"
                            aria-labelledby="contained-modal-title-vcenter"
                            centered
                            show={showModal}
                            onHide={handleClose}
                            key={id}
                        >
                            <Modal.Header closeButton className="border-dark">
                                <Modal.Title className="" id="modal-title">
                                    {name}
                                </Modal.Title>
                            </Modal.Header>

                            <Modal.Body className="container">
                                <p>
                                    {summary}
                                </p>

                                <br />

                                <p>
                                    {techSkills}
                                </p>
                            </Modal.Body>
                            <Modal.Footer className="modal-bg border-dark">
                                <Button id="modal-button" className="" target='_blank' rel='noreferrer' href={url}>View live app here!</Button>
                                <Button id="modal-button" className="" target='_blank' rel='noreferrer' href={gitHub}>
                                    <span className='bi bi-github work-icon'></span>
                                </Button>
                            </Modal.Footer>
                        </Modal>
                    );
                })}
            </div>
        </div>
    );
}
1 Answers

The state in your updated example is still a boolean which is either truth of false. If any button is pressed all modals will open. You can change this state to store a id instead. When button is pressed set id of that item, when modal is closed set state to undefined. See code below, with changes. The important changes are const handleShow = (id) => setShowModal(id); <Button onClick={()=>handleShow(data.id)} show={showModal === id}

// useState variables to display modals
const [showModal, setShowModal] = useState(undefined);
const handleClose = () => setShowModal(undefined);
const handleShow = (id) => setShowModal(id);

return (
    <div className='container'>
        <div className='row'>
            {projectData.map((data) => {
                return (
                    <div className='col-3 d-flex mb-4' key={data.id}>
                        <Button onClick={()=>handleShow(data.id)} className="project-card card p-0 border-5 border-dark shadow-lg">
                            <img className='card-img shadow-lg' src={data.photo} alt={data.name} >
                            </img>
                        </Button>


                    </div>
                );
            })}
            {projectData.map(({id, name, summary, techSkills, url, gitHub}) => {
                return (
                    <Modal
                        {...props}
                        size="lg"
                        aria-labelledby="contained-modal-title-vcenter"
                        centered
                        show={showModal === id}
                        onHide={handleClose}
                        key={id}
                    >
                        <Modal.Header closeButton className="border-dark">
                            <Modal.Title className="" id="modal-title">
                                {name}
                            </Modal.Title>
                        </Modal.Header>

                        <Modal.Body className="container">
                            <p>
                                {summary}
                            </p>

                            <br />

                            <p>
                                {techSkills}
                            </p>
                        </Modal.Body>
                        <Modal.Footer className="modal-bg border-dark">
                            <Button id="modal-button" className="" target='_blank' rel='noreferrer' href={url}>View live app here!</Button>
                            <Button id="modal-button" className="" target='_blank' rel='noreferrer' href={gitHub}>
                                <span className='bi bi-github work-icon'></span>
                            </Button>
                        </Modal.Footer>
                    </Modal>
                );
            })}
        </div>
    </div>
);
Related