Creating Higher-Order Component

Learn to refactor our code from the previous chapter to make a higher-order component in this lesson.

We'll cover the following

Creating reusable higher-order component

At the bottom of this lesson, we have the test-driven-carousel project from the previous chapter, take a look at the Carousel component. In addition to rendering a somewhat complex DOM tree, it also has one piece of state and two event handlers that manipulate that state. Let’s try building an HOC that encapsulates that logic.

  • Well-implemented HOCs tend to be highly reusable, and this one will be no exception. It’ll manage the state for any component with an “index” prop, meaning a number that can go from 0 up to some limit. Call it HasIndex. Start with a minimal dummy implementation that you can run tests against:

    // src/HasIndex.js
    import React from 'react';
    export default (Component, indexPropName) =>
      class ComponentWithIndex extends 
    React.PureComponent {
        static displayName =
          `HasIndex(${Component.displayName ||})`;
        render() {
          return <Component {...this.props} />;
  • To replace the slideIndex logic in Carousel, we need HasIndex to provide three props to the wrapped component: the index itself (with the given indexPropName), an increment function, and a decrement function. To support wrap-around, the increment and decrement functions should accept an upper bound argument. Write a test suite with those requirements:

    // src/tests/HasIndex.test.js
    import React from 'react';
    import { shallow } from 'enzyme';
    import HasIndex from '../HasIndex';
    describe('HasIndex()', () => {
      const MockComponent = () => null;
      MockComponent.displayName = 'MockComponent';
      const MockComponentWithIndex = HasIndex(MockComponent, 'index');
      it('has the expected displayName', () => {
      let wrapper;
      beforeEach(() => {
        wrapper = shallow(<MockComponentWithIndex />);
      it('has an initial `index` state of 0', () => {
      it('passes the `index` state down as the `index` prop', () => {
        wrapper.setState({ index: 1 });
      it('has an `index` state of 2 on decrement from 3', () => {
        wrapper.setState({ index: 3 });
      it('has an `index` state of 1 on increment', () => {
      it('has the max `index` state on decrement from 0', () => {
        wrapper.setState({ index: 0 });
      it('has the min `index` state on increment from the max', () => {
        wrapper.setState({ index: 2 });
  • Then try modifying the implementation to meet those requirements. You should end up with something like this:

Get hands-on with 1200+ tech skills courses.