React Higher Order Components in 3 Minutes
Grasp this useful pattern to stop repeating logic in React Components! 😎
What? permalink
A pattern for when we find ourselves repeating logic across components. They are not part of the React API.
What? permalink
They are functions that take components and return new components!
When? permalink
When you’re repeating patterns/logic across components.
Examples;
- Hooking into/subscribing to a data source
- Adding interactivity to UI (also achieved with wrapper/render props)
- Sorting/filtering input data
A Silly Example permalink
We have a Mouse component.
const Mouse = () => (
<span className="mouse" role="img">🐭</span>
)Let’s make it Draggable using GreenSock’s Draggable module.
class Mouse extends Component {
componentDidMount = () => new Draggable(this.ELEMENT)
render = () => (
<span className="mouse" role="img" ref={e => (this.ELEMENT = e)}>🐭</span>
)
}
We add Cat 😺
const Cat = () => (
<span className="cat" role="img">😺</span>
)That needs to be Draggable too ✋ Opportunity for a Higher Order Component(HOC).
const withDrag = Wrapped => {
class WithDrag extends Component {
componentDidMount = () => new Draggable(this.ELEMENT)
render = () => {
return (
<span className="draggable__wrapper" ref={e => (this.ELEMENT = e)}>
<Wrapped {...this.props} />
</span>
)
}
}
WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})`
return WithDrag
}Our HOC takes a Component and returns a new Component passing props.
Many HOCs inject new props alongside those passed through. That is often an indicator of whether a HOC is suitable. If we aren’t injecting props, we could likely use a wrapper component or render props.
For our HOC, we could achieve the same result with render props. You could argue that a HOC is not suitable. But this is a “silly” example to get you familiar with looking at HOCs. It’s a little more fun than looking at hooking into a data source too! 😉
Let’s apply this HOC to Cat and Mouse 👍
const Mouse = () => (
<span className="mouse" role="img">🐭</span>
)
const Cat = () => (
<span className="cat" role="img">😸</span>
)
const DraggableMouse = withDrag(Mouse)
const DraggableCat = withDrag(Cat)
class App extends Component {
render = () => (
<Fragment>
<DraggableCat />
<DraggableMouse />
</Fragment>
)
}
Let’s hook into the onDrag callback and inject the x and y position as props.
const withDrag = Wrapped => {
class WithDrag extends Component {
componentDidMount = () => new Draggable(this.ELEMENT, { onDrag: this.onDrag })
onDrag = e => {
const { x, y } = e.target.getBoundingClientRect()
this.setState({ x: Math.floor(x), y: Math.floor(y)})
}
render = () => {
return (
<span className="draggable__wrapper" ref={e => (this.ELEMENT = e)}>
<Wrapped {...this.props} x={this.state.x} y={this.state.y} />
</span>
)
}
}
WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})`
return WithDrag
}
const Mouse = ({ x, y }) => (
<span className="mouse" role="img">
🐭
{x !== undefined && y !== undefined && (
<span className="mouse__position">{`(${x}, ${y})`}</span>
)}
</span>
)Now the mouse shows its XY position to the user 🤓

We can also pass props to the HOC. And then filter these out before passing through. For example, passing an onDrag callback.
const withDrag = Wrapped => {
class WithDrag extends Component {
componentDidMount = () => new Draggable(this.ELEMENT, { onDrag: this.props.onDrag })
render = () => {
const { onDrag, ...passed } = this.props
return (
<span className="draggable__wrapper" ref={e => (this.ELEMENT = e)}>
<Wrapped {...passed} />
</span>
)
}
}
WithDrag.displayName = `WithDrag(${Wrapped.displayName || Wrapped.name})`
return WithDrag
}
class App extends Component {
render = () => (
<Fragment>
<DraggableMouse onDrag={e => console.info(e.target.getBoundingClientRect())}>
</Fragment>
)
}By using a HOC, our components remain simple and the logic remains in one place. Our components only care about what is being passed to them. We can reuse them elsewhere without them being draggable. This makes things easier to maintain.
DO’s 👍 permalink
- Use when there’s an opportunity to package up a repeating pattern
- Make debugging easier by updating the
displayNameof the returnedComponent - Pass through
propsunrelated to the HOC
DON’Ts 👎 permalink
- Overuse. Another pattern may be more appropriate.
- Mutate the original
Component - Use inside the
rendermethod
NOTES ⚠️ permalink
refs aren’t passed throughstaticmethods must be copied over- Most HOCs can be written with
renderprops and vice versa!
That’s it! permalink
This is a super small intro to Higher Order Components.