DEV Community

Mikkel Kaysen for IT Minds

Posted on • Originally published at insights.it-minds.dk

Higher-Order Components (HOCs) in React, when and why

Higher-Order Components (HOCs) in React is a way of introducing reusability for component logic to stay DRY. Sounds good so let's just get started using using HOCs. Now wait a minute, before you start to introduce HOCs in your app there are some downsides to all this generic goodness.

Currently i am working on a large scale platform written in React and React-Native. The React-Native app is centered around the user, and the React app is centered around controlling the content shown in the app and managing users connected to the platform.

The web platform has grown a lot throughout the year i have been working on it and is now 300000+ lines of code.

From the start of the development there has been a drive around creating generic reusable components to stay DRY. While this is in essence very good, we have found, through the development, that sometimes the genericness of our code would shoot us in the foot.

We originally intended our HOCs to handle all data access to our API so we could separate it from our view logic. While this in essence was a good idea, it introduced some unintended side effects, since parameterized data access was handled with extra props in our HOCs and destroyed the composable nature of HOCs, as more than one HOC could require the same parameters, and these would not get parsed through.

The convention when writing a HOC with props is

render() {
  const { extraProp, ...passThroughProps } = this.props;

  return (
    <WrappedComponent
      {...passThroughProps}
    />
  );
}

which removes the extra props required by the HOC and pass the rest to the Wrapped Component. But what if you compose two or more HOCs that all require extraProp, like so

const enhance = compose(
  withSomeData, // requires extraProp
  withUpdateSomeData, // requires extraProp
);

export const EnhancedComponent = enhance(Component);

only the first HOC will ever get the extra props.

Instead of this approach one could move the responsibility of getting the extra props, to the Wrapped Component like so

const withSomeData = (getExtraProps) => (WrappedComponent) => {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: DataSource.get(getExtraProps(props))
      };
    }

    render() {
      return <WrappedComponent {...this.props} data={this.state.data} />
    }
  }
}

// ... And something similar for withUpdateSomeData

// And now we are able to use it like so

const enhance = compose(
  withSomeData(props => props.extraProps),
  withUpdateSomeData(props => props.extraProps),
);

export const EnhancedComponent = enhance(Component);

this allows the HOCs to be composable even if they require the same extra props, but it moves the responsibility to the wrapped component, which of course is a trade off.

Top comments (0)