What is a Higher-Order Component (HOC)?
A Higher-Order Component (HOC) is a function that takes a component as input and returns a new enhanced component. HOCs allow code reuse, logic abstraction, and component composition in React.
HOCs follow this pattern:
const EnhancedComponent = withSomething(OriginalComponent);
1. Why Use HOCs?
- Code Reusability: Extract shared logic into a single function.
- Separation of Concerns: Keep components focused on UI while HOCs handle logic.
- Enhancing Components: Add features like authentication, theming, logging, etc.
2. Basic Example of an HOC
Letβs create an HOC that adds extra props to a component.
Step 1: Create the HOC
import React from "react";
const withExtraInfo = (WrappedComponent) => {
return (props) => {
return <WrappedComponent extraInfo="This is extra info!" {...props} />;
};
};
export default withExtraInfo;
Step 2: Use the HOC in a Component
import React from "react";
import withExtraInfo from "./withExtraInfo";
const MyComponent = ({ extraInfo }) => {
return <h1>{extraInfo}</h1>;
};
export default withExtraInfo(MyComponent);
β
What happens? The MyComponent now automatically receives extraInfo from the HOC.
3. Practical Use Cases of HOCs
A. Authentication HOC (Protect Routes)
const withAuth = (WrappedComponent) => {
return (props) => {
const isAuthenticated = true; // Simulating authentication
if (!isAuthenticated) {
return <h2>Please log in to access this page.</h2>;
}
return <WrappedComponent {...props} />;
};
};
// Usage:
const Dashboard = () => <h1>Welcome to Dashboard</h1>;
export default withAuth(Dashboard);
B. Logging HOC (Track Component Rendering)
const withLogger = (WrappedComponent) => {
return (props) => {
console.log(`Component ${WrappedComponent.name} is rendering`);
return <WrappedComponent {...props} />;
};
};
// Usage:
const Profile = () => <h1>My Profile</h1>;
export default withLogger(Profile);
Every time Profile renders, it logs to the console!
C. Fetch Data HOC
import React, { useEffect, useState } from "react";
const withDataFetching = (url) => (WrappedComponent) => {
return (props) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, []);
return data ? <WrappedComponent data={data} {...props} /> : <h3>Loading...</h3>;
};
};
// Usage:
const UsersList = ({ data }) => (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
export default withDataFetching("https://jsonplaceholder.typicode.com/users")(UsersList);
The UsersList component automatically gets user data!
4. HOCs vs. Render Props vs. Hooks
| Feature | HOCs | Render Props | Hooks |
|---|---|---|---|
| Code Reuse | β Yes | β Yes | β Yes |
| Readability | β Can get messy | β Better | β Best |
| Performance | β οΈ Can cause re-renders | β More control | β Efficient |
| Modern React | π« Less recommended | β Okay | β Best choice |
π Hooks (like useEffect, useContext) have mostly replaced HOCs in modern React, but HOCs are still useful in class-based components!
5. When to Use HOCs?
β Use HOCs when:
- You need to reuse logic across multiple components.
- Your project uses class components.
- You want to abstract complex logic (e.g., authentication, permissions, logging).
β Avoid HOCs when:
- You are using modern React with hooks (
useEffect,useContext). - You have only a single-use case (directly placing logic in the component may be simpler).