React.JS Quiz
Answer:
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:
1 2 3 4 5 6 7 |
[crayon-6733b34bb5217063771712 inline="true" class="language-js hljs"]DOM.render( <span class="xml"><span class="hljs-tag"><<span class="hljs-title">LazyLoad</span>></span> <span class="hljs-tag"><<span class="hljs-title">img</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"https://media.giphy.com/media/HhvUpQhBWMtwc/200.gif"</span>/></span> <span class="hljs-tag"><<span class="hljs-title">img</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"https://media2.giphy.com/media/3oEduUDvycvu3GYkdG/200w.gif"</span>/></span> <span class="hljs-tag"><<span class="hljs-title">img</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"https://media0.giphy.com/media/142UITjG5GjIRi/200w.gif"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">LazyLoad</span>></span>, document.body)</span> |
[/crayon] Creating an HOC means handling this.props.children in the Component’s code:
interactive example can be found at https://goo.gl/ns0B6j
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
[crayon-6733b34bb521b113912233 inline="true" class="language-js hljs"]<span class="hljs-keyword">class</span> LazyLoad extends Component { constructor(p){ super(p) <span class="hljs-keyword">this</span>.state = { loaded:<span class="hljs-number">0</span> } <span class="hljs-keyword">this</span>._scroll = <span class="hljs-keyword">this</span>._scroll.bind(<span class="hljs-keyword">this</span>) } _scroll(){ <span class="hljs-keyword">let</span> el = DOM.findDOMNode(<span class="hljs-keyword">this</span>) <span class="hljs-keyword">let</span> {top} = el.getBoundingClientRect() <span class="hljs-keyword">let</span> viewportHeight = <span class="hljs-built_in">Math</span>.max(document.documentElement.clientHeight, window.innerHeight || <span class="hljs-number">0</span>) <span class="hljs-keyword">if</span>(top < (viewportHeight + <span class="hljs-keyword">this</span>.props.top)) { window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-keyword">this</span>._scroll) <span class="hljs-keyword">this</span>.setState({loaded:<span class="hljs-number">1</span>}) } } componentDidMount(){ window.addEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-keyword">this</span>._trackYPosition) <span class="hljs-keyword">this</span>._scroll() } componentWillUnmount(){ window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-keyword">this</span>._trackYPosition) } render(){ <span class="hljs-keyword">let</span> {children} = <span class="hljs-keyword">this</span>.props, {loaded} = <span class="hljs-keyword">this</span>.state <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag"><<span class="hljs-title">div</span>></span> {loaded && children} <span class="hljs-tag"></<span class="hljs-title">div</span>></span> } } LazyLoad.defaultProps = { top: 100 } </span> |
- 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.
- 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.
- 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.
- 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:
1 2 3 4 5 6 |
[crayon-6733b34bb522d236201155 inline="true" class="language-js hljs"]<HOC> <span class="xml"><span class="hljs-tag"><<span class="hljs-title">div</span>></span>some<span class="hljs-tag"></<span class="hljs-title">div</span>></span> <span class="hljs-tag"><<span class="hljs-title">span</span>></span>children<span class="hljs-tag"></<span class="hljs-title">span</span>></span> <span class="hljs-tag"><<span class="hljs-title">Props</span>/></span> <span class="hljs-tag"></<span class="hljs-title">HOC</span>></span> </span> |
[/crayon] 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.
If you want to explore more, visit our React.JS edu & tutorials section!
Below are some examples:
Restaurant Ordering App in ReactJS
CMS in ReactJS and Ruby on Rails