An introduction to HOC

A higher-order component in React is a pattern used to share common functionality between components without repeating code. A higher-order component is actually not a component though, it is a function. A HOC function takes a component as an argument and returns a component. It transforms a component into another component and adds additional data or functionality. In short:

const NewComponent = (BaseComponent) => {

// ... create new component from old one and update

return UpdatedComponent

}

Two HOC’s implementations that you may be familiar with in the React ecosystem are connect from Redux and withRouter from React Router. The connect function from Redux is used to give components access to the global state in the Redux store, and it passes these values to the component as props. The withRouter function injects the router information and functionality into the component, enabling the developer access or change the route.

Creating and maintaining a resume isn’t fun. Instead, let us generate an awesome CV for you :) Resume Builder >

The higher-order component pattern

A higher-order component is a function that takes a component as an argument and returns a component. This means that a HOC will always have a form similar to the follow:

The higherOrderComponent is a function that takes a component called WrappedComponent as an argument. We create a new component called HOC which returns the <WrappedComponent/> from its render function. While this actually adds no functionality in the trivial example, it depicts the common pattern that every HOC function will follow. We can invoke the HOC as follows:

const SimpleHOC = higherOrderComponent (MyComponent);

A basic HOC by example

Now we will extend our basic higher-order component pattern to inject data into our wrapped.

Our team has actually figured out the secretToLife which turns out to be the number 42 . Some of our components need to share this information, and we can create a HOC called withSecretToLife to pass it as a prop to our components.

Notice that this HOC is almost identical to our basic pattern. All we have done is add a prop secretToLife={42} , which allows the wrapped component to access the value by calling this.props.secretToLife .

The other addition is that we spread the props passed to the component. This ensures that any other props that are passed to the wrapped component will be accessible via this.props in the same manner they would be called if the component was not passed through our higher-order component function.

Our WrappedComponent , which is just an enhanced version of <DisplayTheSecret/> , will allow us to access secretToLife as a prop.

A practical HOC by example

Now that we have a solid grasp on the fundamental pattern for HOC, we can build one that is practical for a real application. A higher-order component has access to all the default React API, including state and the lifecycle methods.

The functionality of our withStorage HOC will be to save/load the state of a component, allowing us to quickly access and render it on a page load.

At the top of withStorage we have a single item in the component’s state which tracks if localStorage is available in the given browser. We use the componentDidMount lifecycle hook which will check if localStorage exists in the checkLocalStorageExists function. Here it will test saving an item and set the state to true if it succeeds.

We also add three functions to our HOC — load , save , and remove . These are used to directly access the localStorage API if it is available. Our three functions on the HOC are passed to our wrapped component to be consumed there.

Now we will create a new component to be wrapped in our withStorage HOC. It will be used to display a user’s username and favorite movie. However, the API call to get this information takes a very long time. We can also assume that these values will never change once set.

To ensure we have a great user experience, we will make this API call only if the values haven’t been saved. Then every time the user returns to the page, they can access the data immediately instead of waiting for our API to return.

Inside the componentDidMount of our wrapped component, we first try to access the username and favoriteMovie from localStorage . If the values do not exist, we make our expensive API call named this.props.reallyLongApiCall . Once this function returns, we save the username and favorite to localStorage and update the component’s state to display them on the screen.

Higher-order component considerations