// Tutorial //

A Quick Intro to React's Higher-Order Components

Published on May 12, 2018
Default avatar
By Patrick Moriarty
Developer and author at DigitalOcean.
A Quick Intro to React's Higher-Order Components

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

When you pass a component to a function and it returns a new component, it’s called a higher-order component (HOC). If that sounds simple, it is! And your code will be simpler for using them.

Over the course of this post, you’ll see how the higher-order component abstraction will enable your work to be more readable, reusable, and composable.

Some Terms

Before we move forward, let’s define what it is we’re creating a higher-order version of. While you might see these definitions used interchangeably, it’s important to be aware of their differences:

  • Node: an HTML element that has been mounted on the DOM. Your browser is rendering it, and JavaScript can manipulate it.
  • Instance: a runtime instance of a component class. These are represented as JavaScript objects in memory.
  • Element: a bit of markup that describes a node or a would-be instance. In React, these are transpiled to JavaScript objects, which in turn become instances at runtime.
  • Component: an abstraction over an element. They might carry some internal state, and they may behave differently depending on the props they receive. When asked to render, components return elements.
  • Higher Order Component (HOC): an abstraction over a component. When given a component (and perhaps some other parameters), they return a new component.

Diving In

Say we’re about to start work on our app’s user page. We know what our User object looks like, but we haven’t quite decided what kind of authorization we’d like to use. How can we avoid some heartache later when we determine the right way to go? How do we anticipate the possibility of changing our minds in three months when the page is already finished?

We can start with a simple HOC function named withUser. We want this function to wrap around any component we pass to it and provide our User object as a prop.

const withUser = WrappedComponent => {
  class WithUser extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        user: sessionStorage.getItem("user")
      };
    }
    render() {
      return <^>{...this.props} />;
    }
  }

  return WithUser;
};<^>

Explained:

  • Our function, withUser, takes any component as an argument.
  • Inside, we create a WithUser Component class that reads the User object from sessionStorage and adds it to state.
  • The render function returns the WrappedComponent as a new element with a user prop from state.
  • We pass outer this.props to the inner WrappedComponent.

Alternatively, if state is unnecessary, it’s recommended to use a functional HOC:

const withUser = WrappedComponent => {
  const user = sessionStorage.getItem("user");
  return props => ;
};

Putting HOCs to use

When we want to access the User object on our page, we can call withUser to wrap the page’s component:

const UserPage = props => (
  <div class="user-container">
    <p>My name is {props.user}!</p>
  </div>
);

export default withUser(UserPage);

And that does it! Our withUser function takes a component as an argument and returns a higher order component. Three months from now, if we decide to change things around, we only have to edit our HOC.

In the Wild

If you weren’t familiar with HOCs before, you might have encountered them without realizing it! Some notable examples:

  • react-redux: connect(mapStateToProps, mapDispatchToProps)(UserPage)
  • react-router: withRouter(UserPage)
  • material-ui: withStyles(styles)(UserPage)

Bonus

The compose function from redux allows multiple HOCs to be composed into one. For example:

import { compose } from 'redux';
// ... other imports

export default compose(
  withStyles(styles),
  withRouter,
  withUser
)(UserPage);

In this case, our styles, router, and user would all be passed to our UserPage component.


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!