/ react

A Simple React Higher Order Component Example

Are Higher Order Components still sound complex to you? Here's a simple example that my persuade you to start using them.

What: A Shared Timer

Let's say we want to add a timer to some of our components. One network listener may want to wake up every minute to poll a service, another display listener may want to move something on screen and so on.

Instead of having each start and stop their timers we can write a higher order component to manage the timers:

import React from 'react';

export default function timer(Component) {
  return class Timer extends React.Component {
    constructor(props) {
      super(props);
      this.state = { ticks: 0 };
    }

    componentDidMount() {
      this.timer = setInterval(this.tick, 1000);
    }

    componentWillUnmount() {
      clearInterval(timer);
    }

    tick = () => {
      this.setState(oldState => ({ ticks: oldState.ticks + 1 }));
    }

    render() {
      const props = Object.assign({}, this.props, { ticks: this.state.ticks });
      return <Component {...props} />
    }
  }
}

Here the timer component starts a timer on mount and clears it on unmount. Now every component that needs a timer would just use the function like this clock:

import React from 'react';
import timer from './timer';

class Clock extends React.Component {
  render() {
    return <p>Ticks = {this.props.ticks}</p>
  }
}

export default timer(Clock);

But It Gets Better

What if you don't care about each tick, and just want to be notified every 5 seconds? (or every minute etc.)

Turns out a slight modification in our Higher Order Component is all we need:

import React from 'react';

export default function timer(n) {
  return function(Component) {
    return class Timer extends React.Component {
      constructor(props) {
        super(props);
        this.state = { ticks: 0 };
      }

      componentDidMount() {
        this.timer = setInterval(this.tick, n * 1000);
      }

      componentWillUnmount() {
        clearInterval(timer);
      }

      tick = () => {
        this.setState(oldState => ({ ticks: oldState.ticks + n }));
      }

      render() {
        const props = Object.assign({}, this.props, { ticks: this.state.ticks });
        return <Component {...props} />
      }
    }
  }
}

And the component using the timer now needs to specify how large does each step need to be when calling the function:

import React from 'react';
import timer from './timer';

class Clock extends React.Component {
  render() {
    return <p>Ticks = {this.props.ticks}</p>
  }
}

export default timer(5)(Clock);

Later as the application grows we could replace all the different intervals with one Timer object that would notify each listener when their time has come. The nice thing about this architecture is that such a change would not affect any of the components using the timer, only the higher order component, which is written just once.

Higher Order Components offer a great way to share code between components. For more information about them I suggest to read the tips in React's documentation here:
https://reactjs.org/docs/higher-order-components.html