React’s higher-order component (or HOC for short) is a code pattern that emerges to help you reuse component logic.
Simply put, a higher-order component is a function that accepts a component and returns a new, enhanced component.
For example, let’s say you have a component that renders a simple greeting as follows:
function App({ greeting }) {
return <h1> {greeting} </h1>;
}
<App greeting="Hello World!">
You can create a higher-order component that takes App
and changes its output as follows:
function higherOrderComponent(BaseComponent) {
return function EnhancedComponent() {
return <BaseComponent greeting="Hola Amigo" />;
};
}
To use the higher-order component, assign its return
value into a variable:
const MyNewHOC = higherOrderComponent(App)
You can then use MyNewHOC
just like you use any other normal component.
<MyNewHOC />
It is recommended that a higher-order component doesn’t affect the output of the base component directly.
The base component should be refactored to include a conditional rendering for its output instead:
function App({ greeting, propFromHOC }) {
if (propFromHOC) {
return <h1> {propFromHOC} </h1>;
}
return <h1> {greeting} </h1>;
}
And the HOC code should be refactored to pass a new prop parameter instead of replacing the old one:
function higherOrderComponent(BaseComponent) {
return function EnhancedComponent() {
return <BaseComponent propFromHOC="Hola Amigo" />;
};
}
Passing different props into the base component is just one use case of HOC.
Other use cases include adding state into function components and adding lifecycle methods to function components.
In fact, there’s a helper library for React called recompose that’s created to give you the most frequently used HOC pattern.
If you find this pattern to be confusing, then you’re right! The HOC pattern is a complex code pattern that trips up even experienced React developers.
Before the release of React hooks, the HOC pattern is frequently used to give more power to React components. You can see examples of HOCs in libraries like React Router and Redux.
Most functionalities that used to be implemented with HOC can now be replaced with hooks.
For example, withRouter()
from React Router can be replaced with useHistory()
, useLocation()
, useRouteMatch()
.
Hooks also provide state and lifecycle methods for React functional components, further reducing the need to use HOC pattern.
Whenever you can, you should use hooks instead of HOCs because hooks are way easier to understand and reduce your code complexity level.