React Higher-Order Components (HOC)
As your React application grows, you may notice that multiple components share similar logic — such as fetching data, handling permissions, or managing state.
Instead of duplicating that logic across components, React provides a powerful pattern called a Higher-Order Component (HOC).
What is a Higher-Order Component?
A Higher-Order Component (HOC) is an advanced React pattern that allows you to reuse component logic by wrapping one component with another.
In simple terms:
A HOC is a function that takes a component as input and returns a new enhanced component.
Syntax:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
WrappedComponent– The original component you want to enhance.higherOrderComponent– A function that adds extra logic or behavior.EnhancedComponent– The new component that includes both original and extra functionality.
Example 1: Basic HOC Example
Let’s say you want multiple components to display loading states before showing content.
Instead of repeating loading logic in every component, you can create a reusable HOC.
import React from "react";
function withLoading(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
if (isLoading) {
return <h3>Loading...</h3>;
}
return <Component {...props} />;
};
}
Now you can use this HOC to wrap any component:
function UserList({ users }) {
return (
<ul>
{users.map((user) => (
<li key={user}>{user}</li>
))}
</ul>
);
}
const UserListWithLoading = withLoading(UserList);
// Usage
function App() {
const users = ["Alice", "Bob", "Charlie"];
return <UserListWithLoading isLoading={false} users={users} />;
}
export default App;
What’s happening:
withLoading()adds conditional rendering logic.- The wrapped component (
UserList) focuses only on displaying data. - Logic (loading) is separated and reusable across different components.
Example 2: HOC for Data Fetching
You can also create a HOC that fetches data and injects it as props.
import React, { useEffect, useState } from "react";
function withDataFetching(WrappedComponent, url) {
return function EnhancedComponent(props) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((result) => {
setData(result);
setLoading(false);
});
}, [url]);
return <WrappedComponent data={data} loading={loading} {...props} />;
};
}
Use it like this:
function PostList({ data, loading }) {
if (loading) return <p>Loading posts...</p>;
return (
<ul>
{data.slice(0, 5).map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
const PostsWithData = withDataFetching(PostList, "<https://jsonplaceholder.typicode.com/posts>");
function App() {
return (
<div>
<h2>Posts</h2>
<PostsWithData />
</div>
);
}
export default App;
Benefits:
- The
PostListcomponent focuses only on rendering UI. - Data fetching logic lives in one reusable HOC.
- You can reuse
withDataFetchingfor any component that needs to fetch data.
Why Use Higher-Order Components?
HOCs are ideal for:
- Reusing logic across multiple components
- Code separation and cleaner architecture
- Enhancing existing components without modifying them
- Conditional rendering and permission handling
- Connecting components to global data sources (like Redux or APIs)
Real-World Examples of HOCs
Some popular libraries use HOCs:
- React Redux →
connect()function - React Router →
withRouter()(deprecated in v6, but widely known) - Recompose → Utility HOCs for handling state and props
Summary Table
| Concept | Description |
|---|---|
| Definition | A function that takes a component and returns a new enhanced component |
| Purpose | To reuse logic and behaviors across multiple components |
| Common Use Cases | Loading states, data fetching, authentication, analytics |
| Modern Alternative | React Hooks (custom hooks are simpler for logic reuse) |
