Quiz

What are higher-order components in React?

Topics
React

TL;DR

Higher-order components (HOCs) in React are functions that take a component and return a new component with additional props or behavior. They are used to reuse component logic. For example, if you have a component MyComponent, you can create an HOC like this:

const withExtraProps = (WrappedComponent) => {
return (props) => <WrappedComponent {...props} extraProp="value" />;
};
const EnhancedComponent = withExtraProps(MyComponent);

HOCs were especially common before Hooks and remain valid in existing code and library APIs such as React Redux's connect. For new function components, custom Hooks usually share stateful logic with less wrapper nesting. An HOC can still be appropriate when the abstraction must return a component or wrap rendering rather than only share logic.


What are higher-order components in React?

HOCs are component-transforming functions: they accept one component type and return another that adds or coordinates behavior.

Definition

Higher-order components (HOCs) are functions in React that take a component as an argument and return a new component. The new component typically wraps the original component and adds additional props, state, or behavior. HOCs are a pattern for reusing component logic.

The current React learning material emphasizes custom Hooks for sharing stateful logic. HOCs are still a valid composition pattern, but they are most common in older codebases and library APIs that need to enhance or wrap a component.

Purpose

HOCs are used to:

  • Share common functionality between components
  • Abstract and reuse component logic
  • Enhance components with additional props or state

Example

Here is a simple example of an HOC that adds an extraProp to a wrapped component:

// Define the HOC
const withExtraProps = (WrappedComponent) => {
const ComponentWithExtraProps = (props) => {
return <WrappedComponent {...props} extraProp="value" />;
};
// Set a useful displayName for debugging in React DevTools
const wrappedName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
ComponentWithExtraProps.displayName = `withExtraProps(${wrappedName})`;
return ComponentWithExtraProps;
};
// Define a component to be wrapped
const MyComponent = (props) => {
return <div>{props.extraProp}</div>;
};
// Wrap the component using the HOC
const EnhancedComponent = withExtraProps(MyComponent);
// Use the enhanced component
const App = () => {
return <EnhancedComponent />;
};
export default App;

In this example, withExtraProps is an HOC that adds an extraProp to MyComponent. The EnhancedComponent now has access to extraProp. The displayName convention withExtraProps(MyComponent) makes the component identifiable in React DevTools.

Common use cases

HOCs remain most relevant where an API needs to wrap rendering or enhance a component type:

  • Authentication: Wrapping components to check if a user is authenticated before rendering.
  • Logging: Adding logging functionality to components.
  • Theming: Injecting theme-related props into components.
  • Data fetching: Fetching data and passing it as props to components.

Best practices

An HOC should preserve the wrapped component's identity contract and make its injected behavior explicit:

  • Do not mutate the original component: Always return a new component.
  • Do not create HOCs inside the render method: Calling withExtraProps(MyComponent) inside another component's render produces a brand-new component type on every render, so React unmounts and remounts the subtree, losing all state and DOM. Apply HOCs at the module level.
  • Set a displayName: Wrap the inner name as HOCName(WrappedName) so React DevTools shows something useful instead of Anonymous.
  • Watch for prop-name collisions: An HOC that injects, say, an extraProp will silently overwrite any extraProp the caller passes in (or vice versa, depending on spread order). Namespace injected props or document them clearly.
  • Forward refs explicitly: Wrapping a component in an HOC means a ref passed by the consumer lands on the wrapper, not the inner component. In React 19, forwardRef is no longer required and ref is now a regular prop on function components, so the simplest fix is to accept ref as a prop and forward it: <WrappedComponent {...props} ref={props.ref} extraProp="value" />. For pre-19 codebases, you'd use React.forwardRef inside the HOC.
  • Use HOCs sparingly: Overusing HOCs can make the code harder to understand and creates deeply nested wrapper trees ("wrapper hell"). Custom hooks usually compose more cleanly.

Alternatives

Modern React offers other reuse patterns that avoid adding a wrapper component when wrapping is unnecessary:

  • Custom hooks: Custom hooks share stateful logic between function components without adding wrapper components to the tree and are usually the simpler option for new code.
  • Render props: A pattern where a component uses a function as a prop to determine what to render.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise 1 of 3
Check your understanding Exercise 1 of 3

Which definition is a higher-order component?