0

So I am mapping over an array of items, and am wanting to open up a unique Modal for whichever one is clicked. For some reason, if I click any of the items, a Modal pops up for each of the items. Here is my code

const PrivateProjects = props => {
    const [show, setShow] = useState(false);

    const openModal = () => {
        setShow(true)
    }

    return (
        <div className='projectContainer'>
            {privateProjects.map((project, index) => (
                <div className='lightbox' onClick={() => {openModal()}}>
                    <div className='project'>
                        <h5>{project.name}</h5>
                        <img src={project.image} alt='hibiscus project' />
                    </div>
                    <MyModal title={project.name} img={project.image} show={show} onHide={()=> {setShow(null)}}/>
                </div>
            ))}
        </div>
    )
}

export default PrivateProjects;

Here is MyModal

import React from 'react';
import Modal from 'react-bootstrap/Modal';
import {Button} from 'react-bootstrap';

const MyModal = (props) => {
    console.log(props);

    return (
      <Modal
        {...props}
        size="lg"
        aria-labelledby="contained-modal-title-vcenter"
        centered
      >
        <Modal.Header closeButton>
          <Modal.Title id="contained-modal-title-vcenter">
            {props.title}
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <img src={props.img} />
          <p>
            Cras mattis consectetur purus sit amet fermentum. Cras justo odio,
            dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac
            consectetur ac, vestibulum at eros.
          </p>
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={props.onHide}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }

export default MyModal;

Also, the buttons to close the modal aren't working either, only the escape key works. Not sure where I am messing up with that.

P.S. I took out the imports and array of objects for the sake of visibility, because it's a lot of data and works fine.

here is a pic of what happens with the modals

2 Answers 2

2

This is because they are all using the same show state.

The code below is similar to the structure you have after map is executed:

<MyModal title={project.name} img={...} show={show} />
<MyModal title={project.name} img={...} show={show} />
<MyModal title={project.name} img={...} show={show} />

So, when show gets true, they all open.

You could solve this by using different states for each of the Modals.

Example:

const [show, setShow] = useState([false,false,false])

<MyModal title={project.name} img={...} show={show[0]} />
<MyModal title={project.name} img={...} show={show[1]} />
<MyModal title={project.name} img={...} show={show[2]} />

<button onClick={()=>setShow([false, false, true])}>Open Modal 3</button>
Sign up to request clarification or add additional context in comments.

1 Comment

Great. I found a solution that accompanied your answer, so this was very helpful. Thank you very much! Will post the answer now
1

const PrivateProjects = props => {
    const [show, setShow] = useState([false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]);

    const openModal = (index) => {
        handleChanges(index);
    }

    const handleChanges = (index) => {
            // 1. Make a shallow copy of the items
            let items = [show];
            // 2. Make a shallow copy of the item you want to mutate
            let item = items[index];
            // 3. Replace the property you're intested in
            item = true;
            // 4. Put it back into our array. N.B. we *are* mutating the array here, but that's why we made a copy first
            items[index] = item;
            // 5. Set the state to our new copy
            setShow(items);
    }

    return (
        <div className='projectContainer'>
            {privateProjects.map((project, index) => (
                <div className='lightbox' onClick={() => {openModal(index)}}>
                    <div className='project'>
                        <h5>{project.name}</h5>
                        <img src={project.image} alt='hibiscus project' />
                    </div>
                    <MyModal title={project.name} img={project.image} show={show[index]} onHide={()=> {setShow(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)}}/>
                </div>
            ))}
        </div>
    )
}

export default PrivateProjects;

I feel like there may be a simpler solution, but this is what got it to work for me!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.