Skip to content

Higher-Order Components (or HOCs) in React are functions that take a component and return a new component, enhancing the original in some way:

const EnhancedComponent = hoc(OriginalComponent);

HOCs are very useful for injecting functions, state, and additional data into components as props, as well as wrapping components with styling or more JSX. Using HOCs allow us to only extend the components that need to be extended, while at the same time keeping your codebase modular by separating specialised logic from component implementations.

HOCs are commonly (but not compulsorily) prefixed with with or get. with HOCs are expected to inject functionality whereas get HOCs are expected to inject data into the original component. In most cases you will be applying HOCs to components at export, after your original component is defined:

import { withFunctions } from 'my-module';

class OriginalComponent extends React.Component {
   ...
}
export default withFunctions(OriginalComponent);

Applying a HOC to a component is very simple; we just need to import the required HOC function and wrap the original component with it. The implementation of a HOC is also just as you would expect from a function; the following being our base implementation, returning an enhanced class component:

export function withFunctions(OriginalComponent) {
   return class extends React.Component {
      // make some enhancements
      ...
      render() {
         //return original component with additional props
         return <OriginalComponent {...this.props} />
      }
   }
}

HOC Example

Dependency Injection

In React the need of dependency injection is easily visible. Let's consider the following application tree:

// Title.jsx
export default function Title(props) {
  return <h1>{props.title}</h1>;
}
// Header.jsx
import Title from './Title.jsx';
export default function Header() {
  return (
    <header>
      <Title />
    </header>
  );
}
// App.jsx
import Header from './Header.jsx';
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: 'React Dependency Injection' };
  }
  render() {
    return <Header />;
  }
}

The string "React Dependency Injection" should somehow reach the Title component. The direct way of doing this is to pass it from App to Header and then Header to pass it to Title. However, this may work for these three components but what happens if there are multiple properties and deeper nesting. Lots of components will have to mention properties that they are not interested in. It is clear that most React components receive their dependencies via props but the question is how these dependencies reach that point.

One way to achieve dependency injection is by using higher-order component to inject data.

// inject.jsx
var title = 'React Dependency Injection';
export default function inject(Component) {
  return class Injector extends React.Component {
    render() {
      return <Component {...this.state} {...this.props} title={title} />;
    }
  };
}
// Title.jsx
export default function Title(props) {
  return <h1>{props.title}</h1>;
}
// Header.jsx
import inject from './inject.jsx';
import Title from './Title.jsx';

var EnhancedTitle = inject(Title);
export default function Header() {
  return (
    <header>
      <EnhancedTitle />
    </header>
  );
}

The title is hidden in a middle layer (higher-order component) where we pass it as a prop to the original Title component. That's all nice but it solves only half of the problem. Now we don't have to pass the title down the tree but how this data will reach the enhance.jsx helper.