Higher-Order Components (HOCs) are a React pattern for reusing cross-cutting component logic by wrapping a component. An HOC is a function that takes a component and returns a new component with added behavior (e.g., injecting props, guarding access, subscriptions). They’re common in older/legacy React and some libraries (e.g., Redux connect), even though hooks are the modern default for new code. HOCs enable reuse but can complicate debugging and typing. Test prop collisions and display names.
Higher-order components (HOCs) in React: what are they and when should you use them?
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
Core idea
A higher-order component (HOC) is a function with the shape (Component) => Component. It wraps a “base” component and returns a new component that adds behavior around it (inject props, gate rendering, subscribe/unsubscribe, etc.).
Key rule: an HOC should be pure with respect to its input component (don’t mutate the wrapped component; compose by wrapping).
Concept | What it means | Why it matters |
|---|---|---|
Input | A component ("WrappedComponent") | The HOC enhances behavior around the same UI contract |
Output | A new component ("Enhanced") | You get reuse without copy-pasting logic |
How it works | Wrapper renders | Pass-through preserves flexibility and testability |
Composition |
| Order matters; wrappers layer behavior |
// Minimal HOC: adds logging without changing WrappedComponent
function withLogger(WrappedComponent) {
function WithLogger(props) {
console.log('Rendering', WrappedComponent.displayName || WrappedComponent.name || 'Component');
return <WrappedComponent {...props} />;
}
WithLogger.displayName = `withLogger(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
return WithLogger;
}
function Hello({ name }) {
return <h1>Hello, {name}!</h1>;
}
export const HelloWithLogger = withLogger(Hello);
Common use cases (where HOCs still show up)
Use case | What the HOC does | Typical examples |
|---|---|---|
Inject props | Adds derived/global props to the wrapped component |
|
Access control | Blocks/redirects/returns fallback UI when unauthorized | withAuth / withRoleGuard |
Side-effect wiring | Subscribes and cleans up (events, websockets) around the wrapped component | withSubscription / withWindowListener |
Error boundaries | Wraps with an error boundary component | withErrorBoundary (common in codebases without global boundaries) |
Hard parts / interview-level gotchas
Gotcha | What can go wrong | Fix / best practice |
|---|---|---|
Ref forwarding | Refs don’t automatically pass through wrappers | Use |
Static methods lost | Statics on the wrapped component (e.g., | Hoist statics (e.g., |
Prop clobbering | HOC injects a prop name that collides with caller props | Namespace injected props or document the contract clearly |
Wrapper noise | DevTools shows extra wrapper layers (“wrapper hell”) | Set |
Order sensitivity |
| Be intentional; document composition order |
Creating HOCs in render | New component type each render → remounts/state loss/perf issues | Create HOCs once (module scope) or memoize carefully |
import React from 'react';
// HOC that forwards refs + sets displayName
function withFocusRing(WrappedComponent) {
const WithFocusRing = React.forwardRef(function WithFocusRing(props, ref) {
return (
<div data-focus-ring>
<WrappedComponent ref={ref} {...props} />
</div>
);
});
WithFocusRing.displayName = `withFocusRing(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
return WithFocusRing;
}
Modern guidance
In modern React, custom hooks are usually the first choice for reusing stateful logic because they avoid wrapper nesting and compose more cleanly. HOCs still matter for legacy code, class components, and library APIs built around wrapping (e.g., Redux connect in older setups).
Summary |
|---|
An HOC is a function: |
Prefer custom hooks for new logic reuse; HOCs mostly show up in legacy code and library APIs (e.g., older Redux |
Key gotchas: prop collisions, ref forwarding ( |
Practical scenario
Wrap components with an auth HOC that injects user info and guards rendering.
Common pitfalls
- Prop name collisions between HOC and wrapped component.
- Losing static methods or display names.
- Over-nesting HOCs and reducing readability.
HOCs are powerful but add indirection. Test prop passing and component names in DevTools.