KuroAku
KuroAku

Reputation: 235

How to make an hover state HOC without wraping the component inside a <div>?

I'm trying to write a Higher-order Component which provide a hover property to a component. But I can't make it work with any type of component.

My HOC

function withHover(WrappedComponent) {
  return class extends Component {
    state = {
      hover: false
    }
    onMouseEnter(){
      this.setState({hover: true});
    }
    onMouseLeave(){
      this.setState({hover: false});
    }
    render() {
      return (
        <div onMouseEnter={this.onMouseEnter.bind(this)} onMouseLeave={this.onMouseLeave.bind(this)}>
          <WrappedComponent {...this.props} hover={this.state.hover}/>
        </div>
      )
    }
  }
}

My problem is that I have to wrap the component inside a div for the OnMouse events to work. But when I want, for example, make a <tr> inside a <table> hoverable the <tr> will be wrapped into a <div> which break the <table> logic.

I have thought of passing the HOC's OnMouse events handlers to the wrapped component and call them inside it, but that is not quite convenient because the aim of all this is to save developpement time

So my question is : How to rewrite this HOC to avoid wrapping the initial component inside a <div> ?

Thanks for your time

Upvotes: 0

Views: 589

Answers (2)

Gaurav Saraswat
Gaurav Saraswat

Reputation: 1383

You can just render WrappedComponent from your HOC and passs onMouseEnter and onMouseLeave functions as props and then use them in wrapped components by spread operator on props

Code be like:

function withHover(WrappedComponent) {
  return class extends Component {
    state = {
      hover: false
    }
    onMouseEnter = () => {
      this.setState({hover: true});
    }
    onMouseLeave = () => {
      this.setState({hover: false});
    }
    render() {
      return <WrappedComponent onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} {...this.props} hover={this.state.hover}/>
    }
  }
}

const TableRow = props => {
  return (
    <tr {...props}>
      {props.children}
    </tr>
  )
}
const TableRowWithHover = withHover(TableRow);

Upvotes: 2

Maheer Ali
Maheer Ali

Reputation: 36564

Wrap the child component in fragment in parent Component pass the events to the child elm
Child Elm

class Child extends Component {
  render() {
    return (
      <div
        onMouseLeave={this.props.onMouseLeave || null}
        onMouseEnter={this.props.onMouseEnter || null}
      >
        This is a child Component
      </div>
    );
  }
}

Parent Component(wrapper)

import Child from './child';
class Parent extends Component {
    state = {  }
    onMouseEnter = () =>{
        console.log("mosuse Entered child")
    }
    onMouseLeave = () =>{
        console.log("mosuse left child")
    }
    render() { 
        return ( 
            <>
            <Child onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}></Child>
            </>
         );
    }
}

Upvotes: 1

Related Questions