Frontend Development › UI Frameworks & Components
Higher-Order Component
A function that wraps a component to add behavior.
Also known as: higher-order component, hoc, hoc pattern
A higher-order component (HOC) is a function taking a component and returning an enhanced one: withAuth(Profile), withTheme(Card). Before hooks, HOCs were the reuse mechanism for cross-cutting behaviour — data subscriptions, authorisation, theming, logging — wrapping any component with shared logic.
const Enhanced = withAuth(withTheme(Profile)); // layers of wrapping
Hooks largely superseded them (custom hooks share logic without wrapper hell), but HOCs persist in older codebases and for cases hooks can’t cover (intercepting lifecycle/rendering of wrapped trees, class components). Recognise the pattern on sight; reach for it only where hooks genuinely cannot go.
The classic mistakes:
- Wrapper hell. Stacked HOCs nest DevTools into
withA(withB(withC(Page)))— undebuggable trees and prop indirection. Flatten with hooks where possible. - Prop collisions. HOC-injected props (
data,theme) collide with wrapped components’ own props silently. Namespace injected props or hoist explicitly. - Lost display names. Anonymous wrappers render as
<Unknown>in DevTools. SetdisplayNameon every HOC result. - Ref swallowing. Refs don’t pass through classic HOCs to the wrapped component. Forward refs deliberately.
- Static hoisting gaps.
defaultProps, statics and custom statics don’t copy automatically. Hoist non-React statics explicitly. - Over-wrapping new code. Reaching for HOCs where a hook suffices adds indirection for nostalgia. Hooks for logic reuse; HOCs for render interception and legacy.
- Testing through wrappers. Testing the wrapped export couples tests to every layer. Export the bare component too, and test behaviour per layer.
Its place: legacy reuse and render interception — respected, understood, and mostly replaced by hooks for new logic sharing. Read HOCs fluently; write hooks first.