What does a "Higher-Order Component (HOC)" do?
Definition
A Higher-Order Component (HOC) is a function that takes a component and returns a new component, adding extra functionality to it.
You could say:
A HOC is a "component-over-component" (similar to a decorator or wrapper that adds behavior).
The HOC formula
const EnhancedComponent = withSomething(BaseComponent);where
withSomethingis the HOC function, andBaseComponentis the original component that logic is being added to.
Example: adding user data through a HOC
1. The original component
function UserProfile({ user }) {
return <p>Hello, {user.name}!</p>;
}2. A HOC that passes data into props
function withUser(WrappedComponent) {
return function EnhancedComponent(props) {
const user = { name: 'Tim', age: 25 }; // simulated data
return <WrappedComponent {...props} user={user} />;
};
}3. Using it
const UserProfileWithUser = withUser(UserProfile);
export default function App() {
return <UserProfileWithUser />;
}Now
UserProfileknows nothing about whereusercomes from - the HOC added this behavior "from the outside".
What a HOC does, essentially
A HOC:
- does not modify the original component,
- does not inherit from it,
- but creates a new component that composes the old one with new logic.
A real example: connect() from Redux
import { connect } from "react-redux";
function MyComponent({ user }) {
return <div>{user.name}</div>;
}
export default connect(
(state) => ({ user: state.user })
)(MyComponent);Here
connect()is a classic HOC that links a component to the Redux store and passes the needed data into props.
Example of adding behavior: logging
function withLogger(WrappedComponent) {
return function (props) {
console.log(`Rendering component: ${WrappedComponent.name}`);
return <WrappedComponent {...props} />;
};
}
function Hello({ name }) {
return <h1>Hello, {name}!</h1>;
}
const HelloWithLogger = withLogger(Hello);Now the component's name is logged on every render.
Rules for writing a HOC
- A HOC is a function that returns a component:
const withSomething = (Component) => (props) => <Component {...props} />;- Do not modify the original component! -> Create a new one by wrapping the old one.
- Pass all props through, so as not to "break" the chain:
return <WrappedComponent {...props} extra={data} />;- Preserve the name for easier debugging:
Enhanced.displayName = `withSomething(${WrappedComponent.displayName || WrappedComponent.name})`;What a HOC solves
| Problem | How the HOC solves it |
|---|---|
| Repeating logic across different components | Wraps them with shared behavior |
| Connecting to external data | Adds the needed props (for example, from Redux or context) |
| Handling authorization / roles | Checks access and decides whether to render the component |
| Logging, analytics, error handling | Adds behavior on render |
Downsides of HOCs
| Problem | Description |
|---|---|
| Wrapper nesting | Several HOCs create a "layer cake" (withAuth(withRouter(withTheme(...)))) |
| Hard to track props | A HOC can silently add or override props |
| Non-obvious dependencies | The logic is hidden inside the wrapper |
| Hooks have displaced HOCs | In modern React, almost everything is solved with hooks (useUser(), useAuth()) |
The modern alternative - hooks
The HOC pattern was the main way to reuse logic before hooks existed. Now the same thing is done more simply:
Before (HOC)
const withUser = (Component) => (props) => {
const user = useUser();
return <Component {...props} user={user} />;
};Now (Hook)
function Profile() {
const user = useUser();
return <p>{user.name}</p>;
}Hooks give the same effect - "embedding logic" - but without wrapping components.
Summary
| What | Description |
|---|---|
| Definition | A function that takes a component and returns a new one |
| Goal | Reusing logic without duplication |
| Principle | Component + wrapper = new component |
| Example | connect() from Redux, withRouter() from React Router |
| Alternative | Custom hooks |
| Analogy | A "decorator" that adds capabilities |
Main takeaway:
A HOC is a way to "layer" behavior on top of a component without touching its source code. It was the predecessor of modern hooks, and it is still used when a wrapper is needed "at the component level" rather than "inside it".
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.