Skip to content

ReactJS - Higher order Components

A Higher-Order Component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.

Concretely, a higher-order component is a function that takes a component and returns a new component.

const EnhancedComponent = higherOrderComponent(WrappedComponent);
  • Code Reusability: Share logic across multiple components without repeating code (e.g., subscription to a data source, logging, conditional rendering).
  • Props Manipulation: Add or modify props passed to the wrapped component.
  • Abstraction: Abstract away complex logic or boilerplate, making components simpler.

While Hooks (like useEffect, useContext, and custom Hooks) have become a more common and often simpler way to share stateful logic and side effects, HOCs are still a valuable pattern, especially for cross-cutting concerns that involve modifying the component’s rendering or props in a declarative way.

Let’s create a simple HOC that adds an extra prop to the component it wraps.

import React from 'react';
// This is the Higher-Order Component
const withExtraInfo = (WrappedComponent) => {
// It returns a new functional component
const ComponentWithExtraInfo = (props) => {
const extraInfo = "This info is from the HOC!";
// Pass existing props along with the new prop
return <WrappedComponent {...props} extraInfo={extraInfo} />;
};
// It's good practice to set a display name for debugging
ComponentWithExtraInfo.displayName = `WithExtraInfo(${getDisplayName(WrappedComponent)})`;
return ComponentWithExtraInfo;
};
// Helper function to get the display name of a component
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
export default withExtraInfo;

MyComponent.jsx (The component to be wrapped)

Section titled “MyComponent.jsx (The component to be wrapped)”
import React from 'react';
function MyComponent(props) {
return (
<div>
<h1>Hello, {props.name}!</h1>
<p>{props.extraInfo}</p> {/* This prop comes from the HOC */}
</div>
);
}
export default MyComponent;
import React from 'react';
import MyComponent from './MyComponent';
import withExtraInfo from './withExtraInfo';
// Enhance MyComponent with the HOC
const MyComponentWithExtraInfo = withExtraInfo(MyComponent);
function App() {
return (
<div>
<MyComponentWithExtraInfo name="User" />
</div>
);
}
export default App;

When this App component renders, MyComponentWithExtraInfo will be MyComponent but with an additional extraInfo prop injected by the withExtraInfo HOC. The output would show: Hello, User! This info is from the HOC!

  • Don’t Mutate the Original Component: The HOC should return a new component, not modify the input component.
  • Pass Unrelated Props Through: HOCs should pass through all props that are not relevant to their specific concern using the spread operator ({...props}).
  • Composition: HOCs can be composed together for more complex transformations.
  • Convention: It’s a common convention to prefix HOCs with with, like withRouter or withSubscription.
  • Refs are not passed through: If you need to access a ref on the wrapped component, you’ll need to use React.forwardRef.

HOCs are a powerful pattern for creating reusable component logic. While custom Hooks often provide a more straightforward solution for sharing stateful logic, HOCs remain useful for tasks like modifying props, abstracting rendering logic, or integrating with third-party libraries that expect a component.

Further learning resources: