Sweet HOCs: withHoverState

Mitch Masia
hexient-labs
Published in
3 min readJul 20, 2018

A reusable way to write hover effects in React.

If you’re a UX nut, you’ve probably implemented some sort of “hover” effect. If you’re a React developer, you’ve probably implemented hover effects using the onMouseEnter and onMouseLeave events on a DOM element.

Unfortunately, managing this state over and over can be painful, and add bloat to your React application. What if there was a way to automagically know whether our component is being hovered?

Enter React Powerplug

React Powerplug is a utility library full of components that use render props to help you write fully controlled components without managing state yourself. This is immensely helpful when writing pure functional components and composing additional state, as opposed writing class-based components and managing this.state yourself.

First, let’s look at how we normally have to manage hover state on a div.

// BasicHoverExample.jsimport React, { Component } from 'react'class BasicHoverExample extends Component {
state = {
hovered: false
}
this.updateHoverState = nextHoverState =>
this.setState({ hover: nextHoverState })
render() {
return (
<div
onMouseEnter={() => this.updateHoverState(true)}
onMouseLeave={() => this.updateHoverState(false)}
style={{
backgroundColor: this.state.hovered ? 'red' : 'blue'
}}
>
{/* more content */}
</div>
)
}
}
export default BasicHoverExample

Now this is kind of a contrived example; regardless, managing hover state manually with DOM events is painful.

Now, let’s look at writing a basic higher-order component to manage this same hover state.

// withHoverBasicHOC.jsimport React, { Component } from 'react'const withHoverBasicHOC = BaseComponent =>
class Wrapper extends Component {
state = {
hovered: false
}
this.updateHoverState = nextHoverState =>
this.setState({ hovered: nextHoverState })
render() {
return (
<div
onMouseEnter={() => this.updateHoverState(true)}
onMouseLeave={() => this.updateHoverState(false)}
>
<BaseComponent
{...this.props}
hovered={this.state.hovered}
/>
</div>
)
}
}
export default withHoverBasicHOC

As you can see, withHoverBasicHOC manages the hovered state itself and just applies that state as a prop to the BaseComponent. We can use that HOC like so:

// ComposedBasicHoverExample.jsimport React from 'react'
import withHoverBasicHOC from './withHoverBasicHOC'
const ComposedBasicHoverExample = props => (
<div
style={{
backgroundColor: props.hovered ? 'red' : 'blue'
}}
/>
)
export default withHoverBasicHOC(ComposedBasicHoverExample)

Wow! Awesome right? What a reduction in code and state management in the component where we want a hover state!

Last but not least… let’s see how react-powerplug can make our HOC even simpler with their Hover component that automatically manages events for us!

// withHoverViaPowerplug.jsimport React from 'react'
import { Hover as H } from 'react-powerplug'
export default Base => p => <H>{rp => <Base {...p} {...rp} />}</H>

Wut. With the Hover components, we don’t have to manage any state ourselves which allows us to write our HOC as a pure functional component! To explain the one-liner above, we’re exporting a function that takes a component ( Base ) and the props applied to Base ( p ) and implicitly returns a Hover component, H which uses render props that we apply to Base.

And from there, our integration into our affected component looks like:

// HoverExampleViaPowerplug.jsimport React from 'react'
import withHoverViaPowerplug from './withHoverViaPowerplug'
const HoverExampleViaPowerplug = props => (
<div
{...props.bind}
style={{
backgroundColor: props.hovered ? 'red' : 'blue'
}}
/>
)
export default withHoverViaPowerPlug(HoverExampleViaPowerplug)

Zoinks! And just like that, we have a functional one-liner to apply a hover state onto any component!

--

--

Mitch Masia
hexient-labs

Mitch is a developer, teacher, and entrepreneur building cool things at Guaranteed Rate.