React Higher Order Components (HOC)
Reusing component logic with HOC pattern
🔄 What is a Higher Order Component?
A Higher Order Component (HOC) is a function that takes a component and returns a new enhanced component. It's a pattern for reusing component logic across multiple components without repeating code.
// Simple HOC example
const withGreeting = (Component) => {
return (props) => (
<div>
<h2>Welcome!</h2>
<Component {...props} />
</div>
);
};
Key HOC Concepts
Reusability
Share logic between components
const Enhanced = withAuth(MyComponent);
Composition
Wrap components with extra features
withLoading(withAuth(Component))
Props Injection
Add new props to components
<Component {...props} newProp={value} />
Protection
Add authentication or validation
if (!isAuth) return <Login />;
🔹 Basic HOC Example
A Higher Order Component is a function that wraps another component to add functionality. Here's a simple example that adds a loading state to any component.
// HOC that adds loading functionality
const withLoading = (Component) => {
return ({ isLoading, ...props }) => {
if (isLoading) {
return <div>Loading...</div>;
}
return <Component {...props} />;
};
};
// Original component
const UserProfile = ({ name }) => (
<div>
<h3>User: {name}</h3>
</div>
);
// Enhanced component with loading
const UserProfileWithLoading = withLoading(UserProfile);
// Usage
<UserProfileWithLoading isLoading={false} name="John" />
Output:
User: John
🔹 HOC with Props Manipulation
HOCs can modify, add, or remove props before passing them to the wrapped component. This is useful for data transformation or adding default values.
// HOC that adds timestamp to props
const withTimestamp = (Component) => {
return (props) => {
const timestamp = new Date().toLocaleTimeString();
return <Component {...props} timestamp={timestamp} />;
};
};
// Component that receives timestamp
const Message = ({ text, timestamp }) => (
<div>
<p>{text}</p>
<small>Sent at: {timestamp}</small>
</div>
);
// Enhanced component
const MessageWithTimestamp = withTimestamp(Message);
// Usage
<MessageWithTimestamp text="Hello World!" />
Output:
Hello World!
Sent at: 10:30:45 AM🔹 Authentication HOC
A common use case for HOCs is protecting routes or components that require authentication. The HOC checks if the user is logged in before rendering the component.
// HOC for authentication
const withAuth = (Component) => {
return (props) => {
const isAuthenticated = true; // Check auth status
if (!isAuthenticated) {
return <div>Please log in to continue</div>;
}
return <Component {...props} />;
};
};
// Protected component
const Dashboard = () => (
<div>
<h2>Dashboard</h2>
<p>Welcome to your dashboard!</p>
</div>
);
// Protected dashboard
const ProtectedDashboard = withAuth(Dashboard);
// Usage
<ProtectedDashboard />
Output (when authenticated):
Dashboard
Welcome to your dashboard!
🔹 Composing Multiple HOCs
You can combine multiple HOCs to add different functionalities to a single component. This creates a powerful composition pattern for building complex features.
// Multiple HOCs
const withLoading = (Component) => ({ isLoading, ...props }) =>
isLoading ? <div>Loading...</div> : <Component {...props} />;
const withError = (Component) => ({ error, ...props }) =>
error ? <div>Error: {error}</div> : <Component {...props} />;
// Base component
const DataDisplay = ({ data }) => (
<div>Data: {data}</div>
);
// Compose multiple HOCs
const EnhancedDataDisplay = withLoading(withError(DataDisplay));
// Usage
<EnhancedDataDisplay
isLoading={false}
error={null}
data="Success!"
/>
Output:
🔹 HOC Best Practices
✅ Do's:
- Pass all props: Use {...props} to forward props
- Naming convention: Start HOC names with "with"
- Keep it simple: One responsibility per HOC
- Display name: Set displayName for debugging
❌ Don'ts:
- Don't mutate: Never modify the original component
- Don't use in render: Create HOCs outside components
- Don't copy statics: Remember to copy static methods