By | May 20, 2017
Create Higher Order Components in React

Higher Order Components (HOCs) are the coined term for a custom Component that accepts dynamically provided children. For example, let’s make <LazyLoad /> Component that takes child image tags as children, waits until the <LazyLoad /> Component is scrolled into view, and then loads the images they point to in the background (before rendering them to the DOM).

An HOC accepts children via props:

DOM.render(
    <LazyLoad>
        <img src="../media/1.gif"/>
        <img src="../media/2.gif"/>
        <img src="../media/3/gif" />
    </LazyLoad>,
    document.body)

Creating an HOC means handling this.props.children in the Component’s code:

class LazyLoad extends Component {
    constructor(p){
        super(p)
        this.state = { loaded:0 }
        this._scroll = this._scroll.bind(this)
    }
    _scroll(){
        let el = DOM.findDOMNode(this)
        let {top} = el.getBoundingClientRect()
        let viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
        if(top < (viewportHeight + this.props.top)) {
            window.removeEventListener('scroll', this._scroll)
            this.setState({loaded:1})
        }
    }
    componentDidMount(){
        window.addEventListener('scroll', this._trackYPosition)
        this._scroll()
    }
    componentWillUnmount(){
        window.removeEventListener('scroll', this._trackYPosition)
    }
    render(){
        let {children} = this.props,
            {loaded} = this.state
        return <div>
            {loaded && children}
        </div>
    }
}

LazyLoad.defaultProps = {
    top: 100
}

Noting a few things about this code:

  1. We set up initial state (this.state = {loaded: 0}) in the constructor(). This will be set to 1 when the parent container is scrolled into view.
  2. The render() returns the props.children as child elements when this occurs. Extract the src by using ES6 destructuring, where {props:{src}} creates a variable src with the appropriate value.
  3. We used a single componentDidMount() lifecycle method. This is used because on mount, we’d like the component to check if the HOC is visible.
  4. The largest function of our component, _scroll(), grabs the HOC Component’s DOM element with DOM.findDOMNode() and then gets the elements position. This position is compared to the height of the browser window, and if it is less than 100px from the bottom, then the scroll listener is removed and loaded is set to 1.

This technique is called HOC (Higher Order Component) because we pass in elements as this.props.children when we nest those elements inside the container component:

<HOC>
    <div>some</div>
    <span>children</span>
    <Props/>
</HOC>

All of these nested elements (which can be custom components) are nested under <HOC/>, thus HOC’s code will be able to access them as this.props.children.

Leave a Reply

Your email address will not be published. Required fields are marked *