The Complete Guide to Higher-Order Components in React

Higher-Order Components

A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.

Concretely, a higher-order component is a function that takes a component and returns a new component.

const EnhancedComponent = higherOrderComponent(WrappedComponent);

Whereas a component transforms props into UI, a higher-order component transforms a component into another component.

HOCs are common in third-party React libraries, such as Redux’s connect and Relay’s createFragmentContainer.

In this document, we’ll discuss why higher-order components are useful, and how to write your own.

Use HOCs For Cross-Cutting Concerns

Note: We previously recommended mixins as a way to handle cross-cutting concerns. We’ve since realized that mixins create more trouble than they are worth.

Components are the primary unit of code reuse in React. However, you’ll find that some patterns aren’t a straightforward fit for traditional components.

For example, say you have a CommentList component that subscribes to an external data source to render a list of comments:

class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {
      // "DataSource" is some global data source
      comments: DataSource.getComments()
    };
  }

  componentDidMount() {
    // Subscribe to changes
    DataSource.addChangeListener(this.handleChange);
  }

  componentWillUnmount() {
    // Clean up listener
    DataSource.removeChangeListener(this.handleChange);
  }

  handleChange() {
    // Update component state whenever the data source changes
    this.setState({
      comments: DataSource.getComments()
    });
  }

  render() {
    return (
      <div>
        {this.state.comments.map((comment) => (
          <Comment comment={comment} key={comment.id} />
        ))}
      </div>
    );
  }
}

Later, you write a component for subscribing to a single blog post, which follows a similar pattern:

class BlogPost extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {
      blogPost: DataSource.getBlogPost(props.id)
    };
  }

  componentDidMount() {
    DataSource.addChangeListener(this.handleChange);
  }

  componentWillUnmount() {
    DataSource.removeChangeListener(this.handleChange);
  }

  handleChange() {
    this.setState({
      blogPost: DataSource.getBlogPost(this.props.id)
    });
  }

  render() {
    return <TextBlock text={this.state.blogPost} />;
  }
}

CommentList and BlogPost aren’t identical — they call different methods on DataSource, and they render different output. But much of their implementation is the same:

  • On mount, add a change listener to DataSource.
  • Inside the listener, call setState whenever the data source changes.
  • On unmount, remove the change listener.

You can imagine that in a large app, this same pattern of subscribing to DataSource and calling setState will occur over and over again. We want an abstraction that allows us to define this logic in a single place and share it across many components. This is where higher-order components excel.

We can write a function that creates components, like CommentList and BlogPost, that subscribe to DataSource. The function will accept as one of its arguments a child component that receives the subscribed data as a prop. Let’s call the function withSubscription:

const CommentListWithSubscription = withSubscription(
  CommentList,
  (DataSource) => DataSource.getComments()
);

const BlogPostWithSubscription = withSubscription(
  BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id)
);

The first parameter is the wrapped component. The second parameter retrieves the data we’re interested in, given a DataSource and the current props.

When CommentListWithSubscription and BlogPostWithSubscription are rendered, CommentList and BlogPost will be passed a data prop with the most current data retrieved from DataSource:

// This function takes a component...
function withSubscription(WrappedComponent, selectData) {
  // ...and returns another component...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ... that takes care of the subscription...
      DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      // ... and renders the wrapped component with the fresh data!
      // Notice that we pass through any additional props
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

Note that a HOC doesn’t modify the input component, nor does it use inheritance to copy its behavior. Rather, a HOC composes the original component by wrapping it in a container component. A HOC is a pure function with zero side-effects.

And that’s it! The wrapped component receives all the props of the container, along with a new prop, data, which it uses to render its output. The HOC isn’t concerned with how or why the data is used, and the wrapped component isn’t concerned with where the data came from.

Because withSubscription is a normal function, you can add as many or as few arguments as you like. For example, you may want to make the name of the data prop configurable, to further isolate the HOC from the wrapped component. Or you could accept an argument that configures shouldComponentUpdate, or one that configures the data source. These are all possible because the HOC has full control over how the component is defined.

Like components, the contract between withSubscription and the wrapped component is entirely props-based. This makes it easy to swap one HOC for a different one, as long as they provide the same props to the wrapped component. This may be useful if you change data-fetching libraries, for example.

Don’t Mutate the Original Component. Use Composition.

Resist the temptation to modify a component’s prototype (or otherwise mutate it) inside a HOC.

function logProps(InputComponent) {
  InputComponent.prototype.componentDidUpdate = function(prevProps) {
    console.log('Current props: ', this.props);
    console.log('Previous props: ', prevProps);
  };
  // The fact that we're returning the original input is a hint that it has
  // been mutated.
  return InputComponent;
}

// EnhancedComponent will log whenever props are received
const EnhancedComponent = logProps(InputComponent);

There are a few problems with this. One is that the input component cannot be reused separately from the enhanced component. More crucially, if you apply another HOC to EnhancedComponent that also mutates componentDidUpdate, the first HOC’s functionality will be overridden! This HOC also won’t work with function components, which do not have lifecycle methods.

Mutating HOCs are a leaky abstraction—the consumer must know how they are implemented in order to avoid conflicts with other HOCs.

Instead of mutation, HOCs should use composition, by wrapping the input component in a container component:

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('Current props: ', this.props);
      console.log('Previous props: ', prevProps);
    }
    render() {
      // Wraps the input component in a container, without mutating it. Good!
      return <WrappedComponent {...this.props} />;
    }
  }
}

This HOC has the same functionality as the mutating version while avoiding the potential for clashes. It works equally well with class and function components. And because it’s a pure function, it’s composable with other HOCs, or even with itself.

You may have noticed similarities between HOCs and a pattern called container components. Container components are part of a strategy of separating responsibility between high-level and low-level concerns. Containers manage things like subscriptions and state, and pass props to components that handle things like rendering UI. HOCs use containers as part of their implementation. You can think of HOCs as parameterized container component definitions.

Convention: Pass Unrelated Props Through to the Wrapped Component

HOCs add features to a component. They shouldn’t drastically alter its contract. It’s expected that the component returned from a HOC has a similar interface to the wrapped component.

HOCs should pass through props that are unrelated to its specific concern. Most HOCs contain a render method that looks something like this:

render() {
  // Filter out extra props that are specific to this HOC and shouldn't be
  // passed through
  const { extraProp, ...passThroughProps } = this.props;

  // Inject props into the wrapped component. These are usually state values or
  // instance methods.
  const injectedProp = someStateOrInstanceMethod;

  // Pass props to wrapped component
  return (
    <WrappedComponent
      injectedProp={injectedProp}
      {...passThroughProps}
    />
  );
}

This convention helps ensure that HOCs are as flexible and reusable as possible.

Convention: Maximizing Composability

Not all HOCs look the same. Sometimes they accept only a single argument, the wrapped component:

const NavbarWithRouter = withRouter(Navbar);

Usually, HOCs accept additional arguments. In this example from Relay, a config object is used to specify a component’s data dependencies:

const CommentWithRelay = Relay.createContainer(Comment, config);

The most common signature for HOCs looks like this:

// React Redux's `connect`
const ConnectedComment = connect(commentSelector, commentActions)(CommentList);

What?! If you break it apart, it’s easier to see what’s going on.

// connect is a function that returns another function
const enhance = connect(commentListSelector, commentListActions);
// The returned function is a HOC, which returns a component that is connected
// to the Redux store
const ConnectedComment = enhance(CommentList);

In other words, connect is a higher-order function that returns a higher-order component!

This form may seem confusing or unnecessary, but it has a useful property. Single-argument HOCs like the one returned by the connect function have the signature Component => Component. Functions whose output type is the same as its input type are really easy to compose together.

// Instead of doing this...
const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))

// ... you can use a function composition utility
// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
const enhance = compose(
  // These are both single-argument HOCs
  withRouter,
  connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)

(This same property also allows connect and other enhancer-style HOCs to be used as decorators, an experimental JavaScript proposal.)

The compose utility function is provided by many third-party libraries including lodash (as lodash.flowRight), Redux, and Ramda.

Convention: Wrap the Display Name for Easy Debugging

The container components created by HOCs show up in the React Developer Tools like any other component. To ease debugging, choose a display name that communicates that it’s the result of a HOC.

The most common technique is to wrap the display name of the wrapped component. So if your higher-order component is named withSubscription, and the wrapped component’s display name is CommentList, use the display name WithSubscription(CommentList):

function withSubscription(WrappedComponent) {
  class WithSubscription extends React.Component {/* ... */}
  WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
  return WithSubscription;
}

function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}

Caveats

Higher-order components come with a few caveats that aren’t immediately obvious if you’re new to React.

Don’t Use HOCs Inside the render Method

React’s diffing algorithm (called reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from render is identical (===) to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they’re not equal, the previous subtree is unmounted completely.

Normally, you shouldn’t need to think about this. But it matters for HOCs because it means you can’t apply a HOC to a component within the render method of a component:

render() {
  // A new version of EnhancedComponent is created on every render
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // That causes the entire subtree to unmount/remount each time!
  return <EnhancedComponent />;
}

The problem here isn’t just about performance — remounting a component causes the state of that component and all of its children to be lost.

Instead, apply HOCs outside the component definition so that the resulting component is created only once. Then, its identity will be consistent across renders. This is usually what you want, anyway.

In those rare cases where you need to apply a HOC dynamically, you can also do it inside a component’s lifecycle methods or its constructor.

Static Methods Must Be Copied Over

Sometimes it’s useful to define a static method on a React component. For example, Relay containers expose a static method getFragment to facilitate the composition of GraphQL fragments.

When you apply a HOC to a component, though, the original component is wrapped with a container component. That means the new component does not have any of the static methods of the original component.

// Define a static method
WrappedComponent.staticMethod = function() {/*...*/}
// Now apply a HOC
const EnhancedComponent = enhance(WrappedComponent);

// The enhanced component has no static method
typeof EnhancedComponent.staticMethod === 'undefined' // true

To solve this, you could copy the methods onto the container before returning it:

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // Must know exactly which method(s) to copy :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

However, this requires you to know exactly which methods need to be copied. You can use hoist-non-react-statics to automatically copy all non-React static methods:

import hoistNonReactStatic from 'hoist-non-react-statics';
function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  hoistNonReactStatic(Enhance, WrappedComponent);
  return Enhance;
}

Another possible solution is to export the static method separately from the component itself.

// Instead of...
MyComponent.someFunction = someFunction;
export default MyComponent;

// ...export the method separately...
export { someFunction };

// ...and in the consuming module, import both
import MyComponent, { someFunction } from './MyComponent.js';

Refs Aren’t Passed Through

While the convention for higher-order components is to pass through all props to the wrapped component, this does not work for refs. That’s because ref is not really a prop — like key, it’s handled specially by React. If you add a ref to an element whose component is the result of a HOC, the ref refers to an instance of the outermost container component, not the wrapped component.

The solution for this problem is to use the React.forwardRef API (introduced with React 16.3).


What are Higher-Order Components in React?

If you have been in the React ecosystem for a while, there is a possibility that you have heard about Higher Order Components. Let’s look at a simple implementation while also trying to explain the core idea. From here you should get a good idea of how they work and even put them to use.

Why Higher-Order Components?

As you build React applications, you will run into situations where you want to share the same functionality across multiple components.

For example: you need to manage the state of currently logged in users in your application. Instead of managing that state across all of the components that need that state, you could create a higher-order component to separate the logged in user state into a container component, then pass that state to the components that will make use of it.

The components that receive state from the higher-order component will function as presentational components. State gets passed to them and they conditionally render UI based on it. They do not bother with the management of state.

Let’s see another example. Say you have three JSON files in your application. These files contain different data that will be loaded in your application in three different components. You want to give your users the ability to search the data loaded from these files. You could implement a search feature in all three of the components. This duplication may not be an issue at first, but as your application grows and more components need this functionality, the constant duplication will be cumbersome and prone to problems.

A better way forward is to create a higher-order component to handle the search functionality. With it, you can wrap the other components individually in your higher-order component.

How do Higher-Order Components Work?

The use of higher-order components comes in handy when you are architecturally ready for separating container components from presentation components. The presentation component is often a stateless functional component that takes props and renders UI. A stateless functional components are plain JavaScript functions that do not have states. Here’s an example:

import React from 'react'

const App = ({name}) => {
  return (
    <div>
      <h2>This is a functional component. Your name is {name}.</h2>
    </div>
  )
}

ReactDOM.render(<App name='Kingsley' />, document.getElementById("root"));

The container component does the job of managing of state. The container, in this case, is the higher-order component.

In the search example we talked about earlier, the search component would be the container component that manages the search state and wraps the presentation components that need the search functionality. The presentation components otherwise have no idea of state or how it is being managed.

A Higher-Order Component Example

Let’s start with a basic example. Here’s a higher-order component that transforms and returns usernames in uppercase:

const hoc = (WrappedComponent) => (props) => {
  return (
    <div>
      <WrappedComponent {...props}>
        {props.children.toUpperCase()}
      </WrappedComponent>
    </div>
  )
}

This higher-order component receives a WrappedComponent as an argument. Then it returns new component with props passed to it creating a React element. We call .toUpperCase() on the props.children, to transform the passed props.children to uppercase.

To make use of this higher-order component, we need to create a component that receives props and renders the children.

const Username = (props) => (
  <div>{props.children}</div>
)

Next, we wrap Username with the higher-order component. Let’s store that in a variable:

const UpperCaseUsername = hoc(Username)

In our App component, we can now make use of it like this:

const App = () => (
  <div>
    <UpperCaseUsername>Kingsley</UpperCaseUsername>
  </div>
);

The UpperCaseUsername component is merely a rendering of the Username UI that, in turn, pulls in state from the WrappedComponent acting as the higher-order component.

A More Practical Higher-Order Component

Imagine we want to create a list of locations with a search form that filters them. The JSON will be in flat files and loaded as separate components. Let’s start by loading the data.

Our first component will load locations for our users. We will make use of .map() to loop through the data contained in that JSON file.

import React from 'react'
// Where the data is located
import preload from './locations.json'
// Manages the data
import LocationCard from './LocationCard'

// Renders the presentation of the data
const Location = (props) => {
  return (
    <div>
      <div>
        <div>
          <h2>Preferred Locations</h2>
        </div>
      </div>
      <div>
        {preload.data
          .map(location => <LocationCard key={location.id} {...location} />)}
      </div>
    </div>
  )
}
export default Location

This component will render the data in a LocationCard component. I moved that to a different component to keep things clear. This component is a functional component that handles the presentation of our data. The data (location) from the file is received via props, and each location will be passed down to the LocationCard component.

Now we need a second component that, eventually, also will need search functionality. It will be very similar to the first component we just built, but it will have a different name and load data from a different place.

We want our users to be able to search for items using an input field. The list of items displayed on the app should be determined by the state of the search. This functionality will be shared across the two components we are working on. Thanks to the idea of higher order components, we can create a search container component and wrap it around other components.

Let’s call the component withSearch. This component will render the input field for our search and also manage our searchTerm state. The searchTerm will be passed as props to the wrapped component, which will be used to filter the pulled data:

import React, { Component } from 'react'

const withSearch = (WrappedComponent) => {
  return class extends Component {
    state = {
      searchTerm: ''
    }
    handleSearch = event => {
      this.setState({ searchTerm: event.target.value })
    }

    render() {
      return (
        <div>
          <div>
            <input onChange={this.handleSearch} value={this.state.searchTerm} type="text" placeholder="Search" />
          </div>
          <WrappedComponent searchTerm={this.state.searchTerm} />
        </div>
      )
    }
  }

}
export default withSearch

The searchTerm is given a state of an empty string. The value entered by the user in the search box is obtained and used to set the new state for searchTerm. Next, we pass searchTerm to the WrappedComponent. We will make use of this when filtering the data.

To make use of the higher-order component, we need to make some changes to our presentational component.

import React, { Component } from 'react'
// Where the data is located
import preload from './locations.json'
// Searches the data
import withSearch from './withSearch
// Manages the data
import LocationCard from './LocationCard'

// Renders the presentation of the data
const Location = (props) => {
  const { searchTerm } = props

  return (
    <div>
      <div>
        <div>
          <h2>Preferred Locations</h2>
        </div>
      </div>
      <div>
        {preload.data
          // Filter locations by the inputted search term
          .filter(location => `${location.name} ${location.zone} ${location.region}`.toUpperCase().indexOf(searchTerm.toUpperCase()) >= 0)
          // Loop through the locations
          .map(location => <LocationCard key={location.id} {...location} />)}
      </div>
    </div>
  )
}
export default withSearch(Location)

The first thing we did above is to import the higher-order component. Then we add a filter method to filter the data based on what the user enters in the search input. Last, we need to wrap it with the withSearch component.

Conclusion

Higher-Order Components do not have to be scary. After understanding the basics, you can put the concept to use by abstracting away functionalities that can be shared among different components.


Introduction to higher order components (HOC) in React

This article is intended to give you an understanding of how higher order components work, and when and why to use them. We would keep it beginner friendly, to help you get a better understanding of the concept and why it exists.

Higher order components, in general, are a functional programming methodology. However, this article does not require any functional programming knowledge but required some basic knowledge in React.

We will cover some functional programming concepts that will help you understand HOC in react better.

Let’s begin with the formal definition:

A higher-order component is a function that takes a component and returns a new component.

HOC is not a feature in React or any other programming language, but a pattern evolved from the compositional ( made of components ) nature of react.

Functional programming and higher order functions

A higher order function is a function that accepts another function as an argument. You would have already used the map function which falls under this category.

This is a concept that is derived from the world of functional programming. But why use a functional programming concept in React?

The goal of this pattern is to decompose the logic into simpler and smaller functions that can be reused. A rule of thumb is a function does just one task and does it well. This also avoids side effects ( changing anything that is not owned by the function ) , and makes debugging and maintenance a whole lot easier.

A classic example of functional programming example is the multiplication:

const multiply = (x) => (y) => x * y
multiply(5)(20)

Similarly, a HOC takes another component as argument.

Let’s build a HOC and learn more as we go.

Higher order component in React

Let’s look at some code straight away.

const reverse = (PassedComponent) =>
  ({ children, ...props }) =>
    <PassedComponent {...props}>
      {children.split("").reverse().join("")}
    </PassedComponent>

const name = (props) => <span>{props.children}</span>
const reversedName = reverse(name)
<reversedName>Hello</reversedName>
//=> <span>olleH</span>

The above example takes a component and reverses the content inside it. reverse is a HOC, that takes in an element ( name in the example ), find the content inside that element, reverses it and spits out an element with reversed content.

What shown above is an extremely simple use case for the purpose of understanding the concept.

Two things happen with an HOC

  1. Takes a component as argument
  2. Return something

Let’s have a look at a more practical and complex use case.

In all the apps we have created in the past, if we have to load data from an API, there would be a latency involved.

Typically there is a time lag between when the page is rendered and the actual data is shown. Most of the apps show a loading animation to make the user experience better. Let us build a Loading animation component to demonstrate the concept of HOC.

We will refer to certain parts of the repo as we progress. This is a react app made using create-react-app .

First of all let’s understand how the app works. We use randomuser.me to generate some sample data. Let’s assume that we are building a feed of random users. In App.js we make a request to randomuser.me to get some random data. The request will made inside the componentDidMount function.

componentDidMount() {
    fetch("https://api.randomuser.me/?results=50")
      .then(response => response.json())
      .then(parsedResponse =>
        parsedResponse.results.map(user => ({
          name: `${user.name.first} ${user.name.last}`,
          email: user.email,
          thumbnail: user.picture.thumbnail
        }))
      )
      .then(contacts => this.setState({ contacts }));
  }

The random data from the API is processed since we are only interested in the name, email and the image, we filter it out and set it as the app state. Once we have the data, we pass the contacts to our Feed object as

<Feed contacts={this.state.contacts} />

Here is how our Feed component looks. It simply passes the received contact data into FeedItem. And FeedItem iterates through the data to actually display it.

import React, { Component } from "react";
import FeedItem from "./FeedItem";
import Loading from "./HOC/Loading";

import FeedStyle from "./Feed.css";

class Feed extends Component {
  render() {
    return (
      <div className="justify-content-center align-items-center">
        <FeedItem contacts={this.props.contacts} />
      </div>
    );
  }
}

export default Loading("contacts")(Feed);

You would have noticed that the export statement is different from the normal case. Instead of Feed we export the Feed component wrapped in a Loading component.This is because our Loading HOC is a curried function. Currying is the process of breaking down a function into a series of functions that each take a single argument.

Let’s take a look at our Loading component.

import React, { Component } from "react";

const isEmpty = prop =>
  prop === null ||
  prop === undefined ||
  (prop.hasOwnProperty("length") && prop.length === 0) ||
  (prop.constructor === Object && Object.keys(prop).length === 0);

const Loading = loadingProp => WrappedComponent => {
  return class LoadingHOC extends Component {
    componentDidMount() {
      this.startTimer = Date.now();
    }

    componentWillUpdate(nextProps) {
      if (!isEmpty(nextProps[loadingProp])) {
        this.endTimer = Date.now();
      }
    }

    render() {
      const myProps = {
        loadingTime: ((this.endTimer - this.startTimer) / 1000).toFixed(2)
      };

      return isEmpty(this.props[loadingProp]) ? (
        <div className="loader" />
      ) : (
        <WrappedComponent {...this.props} {...myProps} />
      );
    }
  };
};

export default Loading;

Let’s understand how the component works step by step.

  1. For ease of understanding assume component takes another component ( in our case Feed component ) along with a property contacts
  2. Now the Loading component checks of the loadingProp ( in our case contacts)are empty — The function isEmpty does this.
  3. If it’s empty the Loading component return
<div className="loader" />

We use the classname loader to add some styles and implement the loader.

  1. Else it return the original component with optional addition properties ( in this case myProps

  2. In our example, we have calculated the loading time, for the demonstration purposes and to show that we can pass data back. What you can do using the same is left to your imaginations.

So what happens when we wrap any component in the Loading components along with a property name?

It checks if the passed property name is empty.

If its empty a loading component is returned, if data is present the original component is returned.

That wraps up the implementation of our HOC.

Now that we have understood how to write a HOC lets understand the when and whys.

In a normal case, to implement a loading component, we can check if the corresponding property ( contacts in our example ) in respective component and render a Loading component within the original component.

However, this will lead to redundant code. For example, we have a Feed component controlled by contacts and a List component controlled by name, we would have to check if the data is present in two different cases and render the loading components.

A generic higher order component as shown in the above example avoids this. So in case, we have to implement loading for the List component, in the List.js we can simply do

export default Loading("name")(List);

This is just one application of HOC, you can use it in any way you want. Basically what it does is

  1. Take a component as argument
  2. Return something — this can be anything. Literally anything. You can completely disregard the original component and render something completely new.

What you want to do is up to your imaginations. In short, HOC helps you organise your codebase in a much better way and to decrease code redundancy.

Even Redux uses HOC. The connect statement that you have come across is a HOC that does so many things with the original component.

If you see the same code is written in many places in your codebase there might be a chance to move this to a HOC and make your codebase a lot cleaner.


React Higher Order Components For The Newbie

So you have been coding in React now, and liking it! Great! Did you know about this interesting pattern that you can use in React called, High Order Components? In this post, let’s take a quick look at what Higher Order Components are, and how you can use them in your app?

Yes I know you are like this kid, going “One more new thing to learn?!?!”. Yup trust me it is not hard, and it may come in handy while you code your React App! 🙂 And this is completely optional, you can still build awesome React apps, without Higher Order Components. But it is a common design pattern that you will appreciate and use once you learn what it is.

Background: High Order Functions

The concept of a high order component is not a new one that came with React. In JavaScript we use what is called a High Order Function at times.

A function that accepts and/or returns another function is called a higher-order function.

The diagram below represents a high order function conceptually.

higher-order function

I have written an article on this a while ago, which you can read to get a better understanding of high order functions.

What are high order functions in JavaScript?

What are React Higher Order Components

Now we can extend the same concept into the component architecture in React. In React everything is a component.

A Higher Order Component (HOC) is a function that takes a component and returns a component.

**Note: **HOCs are not really a part of the React API, but this is more of a code pattern that seems to be a good fit with React because of its compositional nature.

The Problem HOCs Solve

Before we get into writing Higher Order Components, it is fair to ask, “What is the problem that HOCs are trying to solve?”

In software development one of the commonly talked about principle is “Don’t Repeat YourSelf” aka. DRY. I have used the DRY principle across multiple languages during my career, and have been advised to do so by experts in the industry. Creating a simple utility function, that is used across several parts of the codebase is something you may have done frequently. You are essentially following DRY by doing so. You are reusing the same utility function, without repeating the code.

In React, one of the ways to achieve DRY across components, is to use the Higher Order Component (HOC) concept. You can share common functionality without repeating code using HOCs.

Structure of HOC

Here is what a HOC looks like in React. The Higher Order Component is essentially a function, that takes in a component as an argument, and returns a new component. It can also render the original component that was passed to it as an argument.

function myHOC (myOtherComponent) {
  return class extends React.Component {
    render() {
      return <myOtherComponent {...this.props}/>
    }
  }
}

In the simple example we see above the _myHOC _is a function that takes in myOtherComponent as a parameter. It then returns a new component. The new component contains _myOtherComponent _as a child in this case.

I Learn by Example!

At this point, you may get an idea of what Higher Order Components are in React and why they are used. To recap:

  • HOC function that takes in a component and returns a new component.
  • It is primarily use to reuse code and follow the DRY principle in React.
  • It is not an API and is a design pattern that fits well within React.

Alright, let’s look at a simple example to understand how HOCs can be put into action.

Create Component

class BlogInformation extends React.Component {
  render() {
    return (
      <div className="blogInfo">
        <h3>Blog Author: {this.props.author}</h3>
        <h3>Article: {this.props.article}</h3>
      </div>
    );
  }
}

I have created a component BlogInformation and this component is a simple class component that displays the name of the author passed to it, and the name of the article written by an author. Both the name and the article are passed to the component as _props. _Simple enough!

Call Component

I am going to call this component from the App.js file and pass the _props _to it.

export default function App() {
  return (
    <div className="App">
      <BlogInformation author="Adhithi" article="New article" />
    </div>
  );
}

So far, we have done nothing special. We just created a component and called that component from the parent component. When we run this code, this what we will see.

Alright, now let’s start to think about enhancing this component. What if I want it to display the author name and “No articles written” in the article section, when no article is passed as prop? If there were no author passed to the component, I want it to display a custom message as well. At this point, the component starts to grow. Keep in mind we are still dealing with a simple feature that we can have all of this in one component, without the use of a HOC. But this post is aiming to illustrate the use of HOC with a simple example to understand how to use it.

Alright, I am going to tweak our _BlogInformation _component a little bit.

class BlogInformation extends React.Component {
  render() {
    return (
      <div className="blogInfo">
        <h3>Blog Author: {this.props.author}</h3>
        <h3>Article:{" "}
          {this.props.article ? this.props.article : "No articles written"}
       </h3>
      </div>
    );
  }
}

We are going to display “No articles written” if the article was not passed in the props.

Create Higher Order Component

Now is a good chance to create a HOC for the rest of the changes.

const myHOCFunction = MyComponent => {
  return class extends MyComponent {
    render() {
      if (this.props.author) {
        return <MyComponent {...this.props} />;
      } else {
        return (
          <div className="UserInfo">
            <h3>There are no authors at this time</h3>
          </div>
        );
      }
    }
  };
};

export default myHOCFunction(BlogInformation);

Here is a summary of the code above:

  • We have created a HOC _myHOCFunction, _that takes in a component and returns a new component.
  • This function checks if the author has been passed in the _props _to the component.
  • If the _author _exists, then it renders the component that was passed with no changes.
  • When the _author _information is unavailable, it renders a new component with a custom message.
  • Towards the end, we are invoking the HOC by passing in the _BlogInformation _component as a parameter.

Now, anytime the _BlogInformation _component is called, it will go the HOC myHOCFunction and render instead. You may now get the idea on why HOC can be useful to you on large React projects. You maybe able to create HOCs to reuse a ton of code, that would have otherwise been repetitive.

To see this working, you can go to the code sandbox below:

Conclusion

Higher Order Components lets your abstract your code, and once you get a hang of it, you may be using this pattern too often. Again, HOC is just a design pattern, and you can opt to use it or not depending on your coding style and preferences.

#reactjs #web-development #javascript

The Complete Guide to Higher-Order Components in React
42.25 GEEK