Higher-Order Components (HOCs)
Learn Higher-Order Components for cross-cutting concerns and component composition
80 min•By Priygop Team•Last updated: Feb 2026
What are HOCs?
Higher-Order Components (HOCs) are functions that take a component and return a new component with additional props or behavior. They are useful for sharing logic between components.
Basic HOC Pattern
Example
// Basic HOC example
import React from 'react';
// HOC for adding loading state
function withLoading(WrappedComponent) {
return function WithLoadingComponent(props) {
const [loading, setLoading] = React.useState(false);
const [data, setData] = React.useState(null);
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(props.url);
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
React.useEffect(() => {
fetchData();
}, [props.url]);
if (loading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} data={data} />;
};
}
// Component to be enhanced
function UserList({ data }) {
if (!data) return <div>No data available</div>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Enhanced component
const UserListWithLoading = withLoading(UserList);
// Usage
function App() {
return <UserListWithLoading url="/api/users" />;
}
// HOC for authentication
function withAuth(WrappedComponent) {
return function WithAuthComponent(props) {
const [user, setUser] = React.useState(null);
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
// Check if user is authenticated
const checkAuth = async () => {
try {
const token = localStorage.getItem('token');
if (token) {
const response = await fetch('/api/me', {
headers: { Authorization: `Bearer ${token}` }
});
if (response.ok) {
const userData = await response.json();
setUser(userData);
}
}
} catch (error) {
console.error('Auth check failed:', error);
} finally {
setLoading(false);
}
};
checkAuth();
}, []);
if (loading) {
return <div>Checking authentication...</div>;
}
if (!user) {
return <div>Please log in to access this page</div>;
}
return <WrappedComponent {...props} user={user} />;
};
}
// Protected component
function Dashboard({ user }) {
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>This is your dashboard</p>
</div>
);
}
const ProtectedDashboard = withAuth(Dashboard);Advanced HOC Patterns
Example
// Advanced HOC with composition and configuration
import React from 'react';
// HOC for error boundaries
function withErrorBoundary(WrappedComponent) {
return class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="error-boundary">
<h2>Something went wrong</h2>
<button onClick={() => this.setState({ hasError: false })}>
Try again
</button>
</div>
);
}
return <WrappedComponent {...this.props} />;
}
};
}
// HOC for performance monitoring
function withPerformanceMonitoring(WrappedComponent, componentName) {
return function PerformanceMonitoredComponent(props) {
const startTime = React.useRef(Date.now());
React.useEffect(() => {
const endTime = Date.now();
const renderTime = endTime - startTime.current;
console.log(`${componentName} rendered in ${renderTime}ms`);
});
return <WrappedComponent {...props} />;
};
}
// HOC for data caching
function withCache(WrappedComponent, cacheKey) {
return function CachedComponent(props) {
const [cachedData, setCachedData] = React.useState(null);
React.useEffect(() => {
const cached = localStorage.getItem(cacheKey);
if (cached) {
try {
setCachedData(JSON.parse(cached));
} catch (error) {
console.error('Failed to parse cached data:', error);
}
}
}, []);
const updateCache = (data) => {
localStorage.setItem(cacheKey, JSON.stringify(data));
setCachedData(data);
};
return (
<WrappedComponent
{...props}
cachedData={cachedData}
updateCache={updateCache}
/>
);
};
}
// HOC composition
function compose(...hocs) {
return (Component) => {
return hocs.reduce((acc, hoc) => hoc(acc), Component);
};
}
// Usage with multiple HOCs
const EnhancedComponent = compose(
withErrorBoundary,
(Component) => withPerformanceMonitoring(Component, 'UserList'),
(Component) => withCache(Component, 'user-list-cache')
)(UserList);
// HOC with configuration
function withConfig(config) {
return function(WrappedComponent) {
return function ConfiguredComponent(props) {
return (
<WrappedComponent
{...props}
config={config}
/>
);
};
};
}
// Usage
const UserListWithConfig = withConfig({
pageSize: 10,
sortBy: 'name',
enableSearch: true
})(UserList);