简体   繁体   中英

Multiple elements with the same ref, React

I have a problem. It is:

let list = storage.map((element, index, array) => {
  return (
    <li key={index} className="list-element">
      <div className="title-wrapper" onMouseEnter={this.handleMouseEnter}>
        <p className="title">{array[index]['title']}</p>
        <p className="title title-full" ref={node => this.title = node}>Text</p>
      </div>
    </li>
      );
}); 
handleMouseEnter() {
    this.title.style.opacity = "1";
}

So, when mouse enters .title-wrapper I want to set opacity to 1 on .title-full. But no matter on which .title-wrapper mouse enters, always opacity will be set to the last .title-full. The problem is easy to solve with querySelector but I read that using it is bad thing in React, isn't it?

The reason this.title is always set to the last element is because you are setting each element in the loop to this.title , so the last one overwrites the one before it, and so on.

What about just using CSS directly, instead of handling it in React at all? Example:

.title-wrapper:hover .title-full {
  opacity: 1;
}

Just a general comment that refs aren't usually preferred in React (maybe for forms or modals sometimes). What you're emulating is a jQuery-like DOM manipulation approach, which can certainly work but is sidestepping the power of React being state-based, obvious, and easy to follow.

I would typically

this.setState({
   hovered: true
})

in your handleMouseEnter method (and unset it in your mouseOut). Then choose your className based on this.state.hovered

I think going with CSS is definitely the best approach.

Just for anyone running into this issue of multiple refs in another context, you could solve the issue by storing the refs in an array

let list = storage.map((element, index, array) => {
  return (
    <li key={index} className="list-element">
      <div className="title-wrapper" onMouseEnter={() => this.handleMouseEnter(index)}>
        <p className="title">{array[index]['title']}</p>
        <p className="title title-full" ref={node => this.titles[index] = node}>Text</p>
      </div>
    </li>
  );
}); 

handleMouseEnter(index) {
  this.titles[index].style.opacity = "1";
}

Again, you don't need to do this for your use case, just thought it might be helpful for others :D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM