One of the best parts in React development is its functional approach for building user interfaces. This approach allows us to use the Higher-Order Component (HOC) technique. It goes back to Higher-Order Function (HOF) from Functional Programming concept. Thus, this technique’s use will keep your React applications tidy, well structured and easy to maintain. Let’s see some annotations about the topic.
Pure Functions and HOFs
The Functional Programming has a concept called pure function. A function is identified as pure when it adheres to the following properties:
It will always return the same output when given the same input
All the data it deals with are passed as arguments
It doesn’t mutate the given data or any external state to eliminate side effects
/**
* Discover velovity which was used to ride a given distance in a given time.
* @param {number} distance in kilometers (Km)
* @param {number} time in hours (h)
* @return {number} velovity in kilometers per hours (Km/h)
*/
function velocity(distance, time) {
return Math.round(distance / time);
}
// POA -> SP walking [http://bit.ly/2ceImWz]
velocity(1081, 228); //= 5 Km/h
The example above shows a pure function. Once given parameters it will always return the same result and only its parameters are manipulated. I’m secure about the behavior and result. But now, look at the following example:
/**
* @var {number} time in hours (h)
*/
var time = 228;
/**
* Discover velovity which was used to ride a given distance.
* @param {number} distance in kilometers (Km)
* @return {number} velovity in kilometers per hours (Km/h)
*/
function velocity(distance) {
return Math.round(distance / time);
}
// POA -> SP walking [http://bit.ly/2ceImWz]
velocity(1081); //= 5 Km/h
time = 1.25;
velocity(1081); //= 865 Km/h
It’s possible to see that the same function is being called twice with the same parameters and returning two different values. It’s a bad implementation of a function because it violates all points which define a pure function.
Functional Programming has also a technique called Higher-Order Function (HOF) which describes a function that takes other function(s) and returns a function.
/**
* Discover velovity which was used to ride a given distance in a given time.
* @param {number} distance in kilometers (Km)
* @param {number} time in hours (h)
* @return {number} velocity in kilometers per hours (Km/h)
*/
const velocity = (distance, time) => Math.round(distance / time);
/**
* Return a new function which log and returns the result.
* @param {function} fn
* @return {function}
*/
const logResult = (fn) => (...args) => {
const result = fn(...args);
console.log(result);
return result;
};
/**
* Return a new function which formats result.
* @param {function} fn
* @param {function} cb
* @return {function}
*/
const formatResult = (fn, cb) => (...args) => cb(fn(...args));
// normal result
velocity(1081, 228); //= 5
// result will be returned and showed at console
const logVelocity = logResult(velocity);
logVelocity(1081, 228); //= 5 and console.log(5)
// result will be formatted
const velocityFormatted = formatResult(velocity, (result) => ${result} Km/h
);
velocityFormatted(1081, 228); //= "5 Km/h"
// function composition
const logVelocityFormatted = logResult(velocityFormatted);
logVelocityFormatted(1081, 228); //= "5 Km/h" and console.log("5 Km/h")
The example above shows us some HOF examples. “velocity” is the same function used in the pure functions examples, but now it is written in ES2015 syntax. Other functions, called “logResult” and “formatResult”, were created to demonstrate how a HOF works. HOFs can be easily combined. This combination creates a new function with the required roles.
Higher-Order Components
React components are just functions. These functions receive some parameters like properties and children components. As a React component is a function we can use functional programming concepts.
import { createElement, createClass } from 'react';
import ReactDOM from 'react-dom';
const Home = (props) => createElement('p', null, Welcome ${props.user}
);
const authenticate = (component) => createClass({
render() {
const { isAuthenticated, ...rest } = this.props;
if (isAuthenticated) {
return createElement(component, rest);
}
return createElement('p', null, 'Good bye');
}
});
const HomeWithAuthentication = authenticate(Home);
ReactDOM.render(
createElement(HomeWithAuthentication, { isAuthenticated: true, user: 'taltk9' }),
document.getElementById('target')
);
//= <p>Welcome taltk9</p>
import React from 'react';
import ReactDOM from 'react-dom';
const Home = (props) => <p>{Welcome ${props.user}
}</p>;
const authenticate = (component) => (props) => {
const { isAuthenticated, ...rest } = props;
if (isAuthenticated) {
return <component {...rest} />;
}
return <p>{'Good bye'}</p>;
};
const HomeWithAuthentication = authenticate(Home);
ReactDOM.render(
<HomeWithAuthentication isAuthenticated user={'taltk9'} />,
document.getElementById('target')
);
//= <p>Welcome taltk9</p>
The above example shows a component called Home that renders a welcome message. Below that there is a function called authenticate that will receive a component as parameter and returns a new one with authentication roles. It’s a wrapper. This component was called HomeWithAuthentication in the example.
Dan Abramov wrote a post talking about HOC where he says:
A higher-order component is just a function that takes an existing component and returns another component that wraps it.
Basically HOCs manipulate wrapped components (which were passed as parameter) to change and/or abstract its state and props and reuse logic and code. There are some ways to create HOCs that were described at the post React Higher Order Components in depth.
If you need more complete examples to understand the HOC idea I recommend the post Higher Order Components: Theory and Practice. In this post he shows very simple examples that will clear your mind about HOCs.
When do we use HOC?
Put in your mind that a good React development should have a good code reuse. Well-designed HOCs indicate what they actually do (easy comprehension) and allow less complicated code updates (generally need to happen in one place). So, usually HOC are important when:
code needs to be clearer: the developer needs to look at the code and understand what it is doing without looking for a documentation;
application needs to be easier to maintain: rules need to be maintained in one place. Components may receive similar responsibilities (ex.: authentication) and we need a good strategy to update them. Composition is the strategy;
components need to assume different roles: composition is a beautiful stuff of programming. It’s recommended to combine some HOCs to create a new one instead of extending a chain of classes (inheritance);
components should be shared through other applications: using React Native we can build mobile apps as we build web applications. So, if I have a web and mobile application and these applications need to authenticate it in some remote API, for example, I can use HOCs to apply this authentication layer in both application components;
HOCs at the real world
Probably you already used some kind of HOC. If you use redux as a data-flow architecture then you know a function called connect which provides many useful optimizations to prevent unnecessary re-renders.
For a redux usage we have a library called redux-form. It’s a great HOC implementation example. This lib uses a functional concept to let us easily create form components. Validating, controlling, and testing forms with JavaScript is a very trivial action when using react-redux.
Conclusion
Creating functions with well defined rules that receive a component and return a new one is definitely a good way to maintain large React projects. Stateless components can be transformed in stateful components just using HOC techniques. So, building small dumb components which can be combined to allow us a progressive and smart development.
The main HOC idea is to make the components development easier. Just create some rules and, if necessary, combine them to give you a cool development experience. Looking to this Confucius’ quote:
Life is really simple, but we insist on making it complicated.
Let’s make things simple and have some fun!!!
PS.: These annotations have been written just to remember the main topics about HOCs. My expectation is to help whoever is looking for a kickstart to learn about the subject. Please, tell me if you agree or disagree about what I wrote. I’d like to see your opinion.
References and related reading
Thanks to Bruno Konrad, Fuad Saud, Tiárli Oliveira, Matheus Azzi, Fabio Akita, and Will Soares.
We want to work with you. Check out our "What We Do" section!