You may have encountered higher-order components in certain React applications. What are they exactly?
According to the React JS documentation, "A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature." - React Higher-Order Components
In short, a higher-order component or HOC is a component that renders another component with modified properties.
To kick things off, let's create a generic React component with title and body props argument.
import React from "react";
import ReactDOM from "react-dom";
const MainComponent = (props) => (
<div>
<h1>{props.title}</h1>
<p>{props.body}</p>
</div>
);
const rootElement = document.getElementById("root");
ReactDOM.render(
<MainComponent
title="A long time ago.."
body="in a galaxy far, far away."
/>,
rootElement
);
Let's say our application has different components that needs to render different messages to users with different access.
One way is to add conditional rendering logic to each component that makes up our application.
However, this goes against the DRY principle.
That's where higher-order component comes in.
Some of the benefits of using higher-order components are:
const authenticateUser = (WrappedComponent) => {
return (props) => (
<div>
<WrappedComponent {...props} />
</div>
);
};
const JediUser = authenticateUser(MainComponent);
const rootElement = document.getElementById("root");
ReactDOM.render(
<JediUser
title="I have taught you everything I know."
body="And you have become a far greater Jedi than I could ever hope to be."
/>,
rootElement
);
First, we create a regular function, authenticateUser and pass in an argument, WrappedComponent, which will be the component that we wish to access.
Inside the authenticateUser function, we return the new component that we wish to render. That's the higher-order component.
We make use of the spread operator (...props) to pass down all the props of the parent component onto our higher-order-component.
Next we specify a new component JediUser and invoke our authenticateUser function, passing in the component that we wish to wrap (MainComponent) as the argument.
At this current state, our higher-order component serves no real purpose other than taking one component and rendering it.
Let's take it one step further by passing a special prop into it.
const authenticateUser = (WrappedComponent) => {
return (props) => (
<div>
{props.isJedi ? (
<WrappedComponent {...props} />
) : (
<p>"Someday, I will be the most powerful Jedi ever."</p>
)}
</div>
);
};
const JediUser = authenticateUser(MainComponent);
const rootElement = document.getElementById("root");
ReactDOM.render(
<JediUser
isJedi={true}
title="I have taught you everything I know."
body="And you have become a far greater Jedi than I could ever hope to be."
/>,
rootElement
);
In this new higher-order component, we use a ternary operator to conditionally render the WrappedComponent based on isJedi prop's value.
If it is true, the application will render MainComponent and if it is false, a different message will display.
By adding in new props to our higher-order component, we've created a versatile higher-order component that encourages code reusability.
Using this pattern, we can modify and manipulate existing React components without having to rewrite them over and over again.
We can make better use of our time to watch the Star Wars Trilogy instead.