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).