Site Logo

Pixel-in-Gene

Exploring Frontend Development with Design / Graphics / Technology

Patterns of Higher-Order-Components (HOC) in React

react logo

Higher Order Components (HOC) are a direct translation of Higher Order Functions from functional languages. A HOC extends the state / behavior of the inner component in a composable way, so you can add many more extensions without the knowledge of the inner component.

React is particularly suited to support this with minimum friction. The tag structure of JSX also helps in visualizing this in text.

In this blog post, we’ll take a look at many of the use-cases for HOCs. They are all from real projects so you are assured of its practicality!

hoc

Creating HOCs

HOCs can be created in couple of ways:

  1. Stateless functions that return a wrapper class, rendering the inner-component via props.children
  2. Stateless functions that render the component passed via props.children
  3. Regular classes that render the component passed via props.children
  4. Using the @decorator language extension

The code below shows these ways of constructing an HOC for a Guard Component (which we will cover in the next section).

import React from 'react';

// 1. Wrapper function returning a class
export function guardedComponentFunction(condition, Component) {
    return class Guarded extends React.Component {
        render() {
            return condition ? <Component {...this.props} /> : null;
        }
    };
}

// 2. Wrapper function
export const GuardedComponent = ({ condition, children }) => {
    return condition ? children : null;
};

// 3. Class that wraps the component via props.children
export class GuardedComponentClass extends React.Component {
    static get defaultProps() {
        return {
            condition: true,
        };
    }

    static get propTypes() {
        return {
            condition: React.PropTypes.bool,
        };
    }

    render() {
        return this.props.condition ? this.props.children : null;
    }
}

// 4. As a @decorator
function guardWith(condition) {
    return function(Component) {
        return guardedComponentFunction(condition, Component);
    };
}

@guardWith(true)
class ComponentToGuard extends React.Component {
    render() {
        return <h2>Advanced Admin Component</h2>;
    }
}

The possibilities…

1. Guard components

Guard components are most useful when you want to render a component only if a certain condition matches. For example, if you have the Admin area which should only be visible to logged-in admin users, you can protect it with a Guard component. Other names for this type of component are Protected or Conditional or Toggle.

2. If/Else components

This is an extension of the Guard component and adds the ability to handle both true and false conditions. You can also treat this as a Toggle wrapper that shows one or the other depending on the condition. I’ve used this in cases where I’ll show the list of items when the number of items are > 0 and an empty message when = 0.

The code below shows the use of an IfElse component. It is fairly simple and uses the first child as the “true” component and the second one as the “false” component.

// if-else.jsx

import React from 'react';

export function IfElse({ condition, children }) {
    const childrenArray = React.Children.toArray(children);

    const trueChild = childrenArray[0],
        falseChild = childrenArray[1] || null;

    return condition ? trueChild : falseChild;
}

// Somewhere in the app

import { IfElse } from './if-else';
import { ListOfItems, EmptyList } from './list-components';

class SomeAppComponent extends React.Component {
    // ...

    render() {
        const { items } = this.props;

        return (
            <IfElse condition={items && items.length > 0}>
                <ListOfItems items={items} />
                <EmptyList message="There are no items in the list" />
            </IfElse>
        );
    }

    // ...
}

Note: You can also extend the IfElse component to be more general with a SwitchCase component! I’ll leave that as a reader exercise :-) If you feel more adventurous, you can even create looping-constructs as HOCs! Think WhileComponent, ForComponent, etc.

3. Provider components

Provider components (or wrapper functions) allow you to mixin behavior and state and make it available as props on the wrapped component.

If you have used Redux or MobX, the connect() and observer, respectively, work as a Providers (or wrappers). They abstract the details about the connection to the store and make it available as props on the wrapped inner component.

The React-Router is yet another example where a Provider component (RouterContext) takes care of instantiating the inner component(s) and passing the Router details.

The provider component is probably the most versatile of all HOC and can do a variety of things like:

  • Swapping out components based on the Viewport size (enabling responsive components)
  • Handling Authentication and passing credentials to inner components
  • Perform logging or support debug behaviors based on certain lifecycle events or app-specific events
  • Handling analytics and reporting user behaviors
  • Doing dependency injection and passing shared services or data to inner components

To be continued…

Provide JSFiddles for the examples above.

If you already have examples of the above, I will be happy to link it here.

Summary

HOCs are a powerful concept derived from functional languages. It allows you to create composable components that abstract details and make the component tree more declarative. Hope the examples above give you some ideas to extend, discover your own patterns of HOC in your application.

Patterns of Higher-Order-Components (HOC) in React
Pavan Podila
Pavan Podila
July 13th, 2016