1

So I have just started learning react and for my for first little project I decided to make a simple UI using the Marvel API. I have an array that displays all marvel characters that begin with a certain letter, for example; a user inputs 'h' and then they are shown every character that begins with the letter h. When a users clicks a character a modal pops up and displays info about that specific character.

My problem is that when a user clicks on a picture to open the modal all of the modals for every character in the array are opened. I dont know how to make only the modal that is selected to open.

    render () {
var characters = _.map(this.state.characters, (character, i) => {
var pic = character.thumbnail.path
var picExt = character.thumbnail.extension
return (
  <div className="styleResults" key={i}>
    <li><h3>{character.name}</h3></li>
    <div>
      <img src={`${pic}/standard_fantastic.${picExt}`} 
alt={`${character.name}`} onClick={() => this.openModal()}/>
      <Modal isOpen={this.state.isModalOpen} onClose={() => 
      this.closeModal()} contentLabel="marvelModal">
          <div>
            <div><h1>{character.name}</h1></div>
            <div><img className="modalIm" src=
 {`${pic}/standard_fantastic.${character.thumbnail.extension}`} alt=
 {`${character.name}`}/></div>
            <div>{character.description}</div>
          </div>
       <p><button onClick={() => this.closeModal()}>Close</button></p>
      </Modal>
    </div>
  </div>
);
});
return (
  <div>
    <div>
      <div>
        <h2>Enter a Character's Name</h2>
        <input ref="charS" type="text"/>
        <button onClick={ (e) => { this.updateCharSearch(); } 
        }>Search</button>
      </div>
      <div className="CharAndComDiv">
        <h2>Enter a Comic's Name</h2>
        <input ref="comicSearch" type="text"/>
        <button onClick={ (e) => { this.updateComicSearch(); } 
         }>Search</button>
      </div>
    </div>
    <div>
      <div>
        <ul>{characters}</ul>
      </div>
      <div>
        <ul>{comics}</ul>
      </div>
    </div>
  </div>
);
}
    openModal() {
    this.setState({ isModalOpen: true })
}

   closeModal() {
   this.setState({ isModalOpen: false })
  }
};

1 Answer 1

1

Don't create a modal for each character - create one modal that can render any selected character.

For example, store modalOpenIndex which will store the index of the currently opened character or -1 for a closed model. Then move the <Modal to be the last item of the render (not in the map function).

<Modal 
    isOpen={this.state.modalOpenIndex >= 0} 
    onClose={() => this.closeModal()} contentLabel="marvelModal">
Sign up to request clarification or add additional context in comments.

5 Comments

I have moved the modal outside the function but now I cant access the var I have made inside the map function to insert into the modal.
@GANON: What do you mean? you don't need the var inside the map function. You have the currently opened character by using the modalOpenIndex state variable. this.state.characters[modelOpenIndex]
Because I have {character.name} {character.description} inside the modal which is outside of the map function where they are declared, I can no longer access them. They are not declared globally. I can't seem to use the same method of retrieving the name and description as I did before. for example {character.name}. outside of the map function I dont know how to access the parts of the characters array...
if you've replaced isModalOpen with modelOpenIndex (number, index of currently opened modal) like i said, then you can replace character with this.state.characters[modelOpenIndex]. If this doesn't make sense to you then you should read up on how arrays work. modelOpenIndex should be -1 if the modal is closed, or a positive integer specifying which character is currently being displayed in the modal. if the integer is > -1 then you show the modal and render the character at the specified index.
Thank you for the help. I Finally figured it out!

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.