Higher Order Components compose!

TL;DR:

Higher Order Components compose. Once you need to combine multiple enhancing components, Higher Order Components standout. If you only need a single enhancing functionality, all known patterns (view as prop, children functions etc.) will work. Choosing which is a matter of preference and sometimes Higher Order Components are not the best solution for a given problem anyway.

Basics

This is just a very short write-up, to show why Higher Order Components make sense and where they really shine. The concept of Higher Order Components became popular when support for mixins was dropped as ES6 classes were introduced in React. Up to this point, mixins where a way to enhance a React component with additional functionality.

This is also exactly what Higher Order Components do. Enhance a component with functionality. So a Higher Order Component is a function that accepts a component and returns a component. Similar to higher order functions that accept a function and return a function.

Let’s take the following Higher Order Component as an example. It does one thing: transform props and call the wrapped component with the transformed props. Neglect the fact, that the function is not optimized, this implementation is strictly for explanation purposes. So we have a function that accepts a transform function (fn), then wraps a Component and finally transforms the props and calls the Component with these props.

const mapProps = fn => Component => props =>

React.createFactory(Component)(fn(props))

Next we define the mapping function and then enhance a stateless functional component with this transformation capability.

const SomeStatelessFunction = ({ id, updateState,...props }) => {

return <div>

<div>Id: {id}</div>

</div>

}



const Enhanced =

mapProps(({value, ...props}) => ({ ...props, ...{ id: value }}))



const EnhancedStatelessFunction = Enhanced(SomeStatelessFunction)



const App = () => {

return (

<div>

<EnhancedStatelessFunction

value={15}

/>

</div>

)

}

Now you might be thinking, why? You could achieve the same outcome with a simple Component that receives the mapping function and a component as prop and call the component after applying the passed in function. Let’s see how this can be achieved.

const MapProps = ({ fn, view: Component, ...props }) => {

const transformedProps = fn(props)

return (

<Component {...transformedProps} />

)

} const App = () => {

return (

<div>

<MapProps

value='5'

fn={({value, ...props}) => ({ ...props, ...{ id: value }})}

view={SomeStatelessFunction}

/>

</div>

)

}

So yes, the outcome is the same. You could even take it a step further and pass in a child function via JSX.

const SomeStatelessFunction = ({ id,...props }) => (

<div>

<div>Id: {id}</div>

</div>

)



const App = () => {

return (

<div>

<MapProps

value='5'

fn={({value, ...props}) => ({ ...props, ...{ id: value }})}

>

{props => <SomeStatelessFunction {...props} />}

</MapProps>

</div>

)

}

All these approaches work and up to the individual developer to decide which one fits their style best.

Just by looking at these examples, it’s neither obvious nor clear what Higher Order Components can do that other patterns can’t. There are many ways to achieve the same, as seen with the above examples.