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

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!

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).

 1 import React from 'react';
 2 
 3 // 1. Wrapper function returning a class
 4 export function guardedComponentFunction(condition, Component) {
 5     return class Guarded extends React.Component {
 6         render() {
 7             return condition ? <Component {...this.props} /> : null;
 8         }
 9     }
10 }
11 
12 // 2. Wrapper function
13 export const GuardedComponent = ({condition, children})=> {
14     return (condition ? children : null);
15 };
16 
17 // 3. Class that wraps the component via props.children
18 export class GuardedComponentClass extends React.Component {
19 
20     static get defaultProps() {
21         return {
22             condition: true
23         };
24     }
25 
26     static get propTypes() {
27         return {
28             condition: React.PropTypes.bool
29         };
30     }
31 
32     render() {
33 
34         return (this.props.condition ? this.props.children : null);
35     }
36 }
37 
38 // 4. As a @decorator
39 function guardWith(condition) {
40     return function(Component) {
41         return guardedComponentFunction(condition, Component);
42     }
43 }
44 
45 @guardWith(true)
46 class ComponentToGuard extends React.Component {
47     render() {
48         return <h2>Advanced Admin Component</h2>;
49     }
50 }

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.

 1 // if-else.jsx
 2 
 3 import React from 'react';
 4 
 5 export function IfElse({condition, children}) {
 6     const childrenArray = React.Children.toArray(children);
 7 
 8     const trueChild = childrenArray[0],
 9         falseChild = childrenArray[1] || null;
10 
11     return condition ? trueChild : falseChild;
12 }
13 
14 
15 
16 // Somewhere in the app
17 
18 import {IfElse} from './if-else';
19 import {ListOfItems, EmptyList} from './list-components';
20 
21 class SomeAppComponent extends React.Component {
22     // ...
23 
24     render() {
25         const {items} = this.props;
26 
27         return (
28             <IfElse condition={items && items.length > 0}>
29                 <ListOfItems items={items}/>
30                 <EmptyList message="There are no items in the list"/>
31             </IfElse>
32         );
33     }
34 
35     // ...
36 
37 }

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.