Higher Order Component (HOC) Pattern in React
The Higher Order Component (HOC) is a popular pattern in React that allows you to reuse component across different components.
Introduction: Higher Order Functions (HOF)
Certain programming languages (like Javascript) treat functions as first-class citizens. This allow us to treat functions as values and assign them to another variable, pass them as arguments to another function, or even return them from another function.
If you have been playing around with JS for a bit you probably have already made use of HOFs, as it provides us with some inbuilt higher order functions like
map()
, filter()
, reduce()
and so on.array.map(item => ...) // you're passing a function as an argument here!
But this is also a HOF:
const a = b => c => b + c // The following code is equivalent function a (b) { return function (c) { return b + c } } const result = a(2)(4) // 6
It’s important to understand this concept as HOC are based on it.
What are Higher Order Components (HOC)?
A Higher Order Component (HOC) is a function that takes a React Component as an argument and returns a new component with additional functionality. The new component is a wrapper around the original component, and it can be used in the same way as the original component.
HOC is one of the most useful patterns that we can use when working with React applications
Here's an example of a Higher Order Component that adds a
onClick
event to a component:interface WithClickProps { onClick: () => void } const withClick = <T>(Component: FC<T>): FC<T & WithClickProps> => (props: T) => { function handleClick () { console.log('Clicked!') }; return <Component onClick={handleClick} {...props} /> } }
In this example, the
withClick
function takes a component as an argument and returns a new component that has an onClick
event that logs "Clicked!" to the console when the component is clicked.How to use Higher Order Components
Using HOCs in React is easy. You can use them just like any other component, but you need to wrap the original component in the HOC function.
Here's an example of using the
withClick
HOC:interface ButtonProps { children: ReactNode } function Button({ children, ...rest} : ButtonProps) { return <button {...rest}>{children}</button> } // You can reuse HOCs across multiple components const ButtonWithClick = withClick<ButtonProps>(Button) /* // You can reuse HOCs across multiple components const TextWithClick = withClick<TextProps>(Text) */ function App() { return ( <div> <ButtonWithClick>Click me!</ButtonWithClick> </div> ); }
In this example, the
Button
component is wrapped in the withClick
HOC to create a new component called ButtonWithClick
. The ButtonWithClick
component is then used in the App
component to render a button that logs "Clicked!" to the console when clicked.Why use Higher Order Components?
HOCs are a powerful tool for code reuse and composition in React. Here are some benefits of using HOCs:
- Code reuse: HOCs allow you to reuse common functionality across multiple components without duplicating code.
- Composition: HOCs can be composed together to create complex behaviours and functionality.
- Separation of concerns: HOCs can be used to separate concerns by encapsulating functionality into separate components.
Production example
Working at @NPAW we developed a complex app that allowed our users to create custom-made dashboards by using a large set of widgets with different functionalities.
While each widget contained its specific details, some features were shared across all of them (drag&drop, selection, etc.).
We made use of this pattern to keep each functionality isolated (e.g: withDragAndDrop, withSelection…), while also allowing us to compose widgets attending the requirements in a flexible manner.
Common Conventions
There are 2 special conventions to follow when working with HOCs that I’d like to mention.
- HOCs naming should begin with
with...
- All props must be passed down to the component (unless necessary interception for specific cases)
Conclusion
HOCs are a powerful tool for code reuse and composition in React. They allow you to reuse common functionality across multiple components without duplicating code, compose complex behaviours and functionality, and separate concerns by encapsulating functionality into separate components.
I hope that you've found this article helpful and that it has inspired you to start using HOCs in your own React projects.