16

I am currently building a dropdown button to learn React. I have made two onMouseEnter and onMouseLeave events in the parent div to make it visible when hovering it disappear when not. The problem is that those events only stick to parent.

How to make onMouseLeave in React include the child context? Or, how can I keep the state expand be true when hovering on children?

class DropDownButton extends React.Component {
constructor(){
    super();
    this.handleHoverOn = this.handleHoverOn.bind(this);
    this.handleHoverOff = this.handleHoverOff.bind(this);
    this.state = {expand: false};
}

handleHoverOn(){
    if(this.props.hover){
        this.setState({expand: true});
    }
}

handleHoverOff(){
    if(this.props.hover){
        this.setState({expand: false});
    }
}

render() {
    return (
        <div>
            <div className={styles.listTitle}
            onMouseEnter={this.handleHoverOn}
            onMouseLeave={this.handleHoverOff}>
            {this.props.name}
            </div>
            <div>
            {React.Children.map(this.props.children, function(child){
            return React.cloneElement(child, {className: 'child'});
            })}
            </div>
        </div>
     );
}
}
Karl Karl
  • 163
  • 1
  • 1
  • 6

2 Answers2

10

You have two different divs in your DOM that don't overlap; I'll split up render so it's more obvious:

render() {
    return (
        <div>

            <div className={styles.listTitle}
              onMouseEnter={this.handleHoverOn}
              onMouseLeave={this.handleHoverOff}>
                {this.props.name}
            </div>

            <div>
                {React.Children.map(this.props.children, function(child){
                    return React.cloneElement(child, {className: 'child'});
                })}
            </div>

        </div>
     );
}

The div that has the onMouseLeave attached to it does not contain the children; so, when the mouse moves to hover on a child, it leaves the div and this.handleHoverOff is called.

You might consider using CSS to hide the children if they shouldn't be displayed, or conditionally rendering them:

render() {
    return (
        <div className={styles.listTitle}
          onMouseEnter={this.handleHoverOn}
          onMouseLeave={this.handleHoverOff}>
            {this.props.name}
            {this.state.expanded && this.renderChildren()}
        </div>
     );
},

renderChildren() {
    return (
        <div>
            {React.Children.map(this.props.children, function(child){
                return React.cloneElement(child, {className: 'child'});
            })}
        </div>
    );
}
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
5

By using the on mouse leave instead of mouse out and blocking the event on the children I got it reliably working no matter how fast I move through my list items.

https://stackoverflow.com/a/18837002/3302764

JoshuaTree
  • 1,211
  • 14
  • 19