A hoc in React JS is a function that takes a component and returns a new enhanced component. It enables code reuse, logic abstraction, and prop manipulation without modifying the original component.
Hocs are not part of React's core API but are a widely adopted design pattern. They work by wrapping a component in a function that injects additional props or behavior. For example, a hoc can add authentication checks, logging, or data fetching to any component it wraps.
The pattern originated in functional programming and was popularized in React during the class component era. Today, it remains relevant in specific scenarios, though React hooks have largely reduced its necessity.
A hoc is a pure function that accepts a component as input and returns a new component. The returned component renders the original one, often with added props or lifecycle logic.
For example, a hoc called withAuth wraps a component and checks if a user is logged in. If not, it redirects to a login page. The wrapped component receives a user prop and access control logic without needing to handle auth itself.
Here's a minimal implementation:
function withAuth(WrappedComponent) {
return function AuthenticatedComponent(props) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
// Simulate auth check
fetch('/api/auth')
.then(res => res.json())
.then(data => setIsAuthenticated(data.authenticated));
}, []);
return isAuthenticated ? <WrappedComponent {...props} /> : <div>Please log in</div>;
};
}
Hocs fall into categories based on their purpose. The most common are:
Common hoc patterns include:
| Pattern | Purpose | Example Use Case |
|---|---|---|
| withLoading | Displays a spinner while data loads | Wrapping a profile card that waits for user data |
| withErrorBoundary | Catches rendering errors | Protecting a complex dashboard from crashing |
| withFormState | Manages form inputs and validation | Adding shared form logic to multiple input forms |
These patterns are reusable across apps. A single withLoading hoc can be applied to any component that fetches data asynchronously.
Hocs were essential in early React applications using class components. They enabled developers to share logic across many components without duplicating code.
For example, a large e-commerce site might use a withCart hoc to provide cart functionality to product detail pages, checkout screens, and sidebar widgets-all without rewriting the same logic.
According to the React documentation, hocs are particularly useful when you need to:
They're also valuable in libraries. Material-UI uses hocs to inject theme and accessibility props into components, ensuring consistent behavior across the library.
One widespread misunderstanding is that hocs are required for code reuse. This is false. React hooks now offer a simpler, more predictable alternative.
Another issue is naming conflicts. When multiple hocs wrap a component, their props may clash. For example, two hocs both adding a 'theme' prop can cause unexpected behavior. Debugging such issues requires tracing the chain of wrappers.
Hocs create nested component structures. A component wrapped in five hocs becomes deeply nested, making debugging harder. The React DevTools show this as a long chain of wrapper components, obscuring the actual component being inspected.
As a rule of thumb, avoid hocs when you can use a custom hook. The React team explicitly recommends this in their official hooks guide.
Since React 16.8, hooks have become the standard way to share logic. A custom hook like useAuth() replaces the need for a withAuth hoc.
Here's the same authentication logic rewritten as a hook:
function useAuth() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
fetch('/api/auth')
.then(res => res.json())
.then(data => setIsAuthenticated(data.authenticated));
}, []);
return isAuthenticated;
}
// Usage:
function ProfilePage() {
const authenticated = useAuth();
if (!authenticated) return <div>Please log in</div>;
return <div>Welcome, user!</div>;
}
This version is easier to test, debug, and compose. It avoids nesting and doesn't require wrapping components.
One non-obvious benefit: hooks allow conditional execution. You can call useAuth() only when needed, whereas a hoc runs every time the component mounts-even if the logic isn't used.
I've seen teams replace 15+ hocs with 5 custom hooks. The result was faster load times, fewer bugs, and clearer component boundaries. The change wasn't just technical-it improved team collaboration.
Still, hocs aren't obsolete. They remain useful in certain cases, such as:
But for new projects, prefer hooks. The React team emphasizes this in their introduction to hooks.
Understanding the trade-offs helps decide which pattern to use.
| Aspect | hoc in react js | React hooks |
|---|---|---|
| Composition | Wraps components; creates nesting | Composable functions; flat structure |
| Debugging | Harder due to wrapper layers | Easier; direct function calls |
| Testing | Requires rendering wrapper chain | Testable in isolation |
| Reusability | Shared across components via wrapping | Shared via function import |
Use hooks unless you're maintaining old code or building a library that must support older React versions.
Hoc in React JS is a useful pattern for enhancing components through function composition. It enabled complex logic sharing before hooks existed. But today, hooks are the preferred solution for most use cases.
When you see a hoc in a codebase, ask: "Could this be written as a custom hook?" If yes, refactor. The result is cleaner, more maintainable code.