Tutorial

A Quick Intro to React's Higher-Order Components

Published on May 12, 2018
Default avatar

By Patrick Moriarty

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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Patrick Moriarty

author

Still looking for an answer?

Ask a questionSearch for more help

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!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel