To explain Higher Order Components (HOCs), it's important to understand what higher order functions are in JavaScript.
Higher order function
A higher order function is a function that either:
accepts at least one function as argument, or
returns a function, or
both of the above
Higher Order Component (HOC)
A HOC is a function that takes a component as argument and returns a component. This pattern is commonly used to enhance components with additional props and/or functionality.
Let's take a look at an example. We have a Counter
component that accepts 2 props; initialValue
and log
. The initialValue
is used as the starting value of the counter. log
is a function that logs out text.
function Counter({ initialValue, log }) {
const [count, setCount] = useState(initialValue);
const handleClick = () => {
setCount((prevCount) => {
const nextCount = prevCount + 1;
log("Next count:", nextCount);
return nextCount;
});
};
return <button onClick={handleClick}>{count}</button>;
}
We're passing log
as an argument because we want to log out the text we pass in, plus something else, like the current timestamp, and we might want this logging behavior in other components as well.
That's where a HOC is useful.
function withLog(WrappedComponent) {
// adds timestamp to console.log
const log = (...text) => {
console.log(new Date().toISOString(), ...text);
};
return ({ ...wrappedComponentProps }) => (
<WrappedComponent
{...wrappedComponentProps}
log={log}
/>
);
}
Notice how withLog
returns a component (i.e. a function that returns JSX) that accepts wrappedComponentProps
? These are Counter
's props. However, withLog
is responsible for passing log
to WrappedComponent
.
Next, we need to call withLog
with Counter
as argument.
const EnhancedCounter = withLog(Counter);
function App() {
return <EnhancedCounter initialValue={1} />;
}
When using EnhancedCounter
, we don't pass in log
as this is already taken care of by withLog
.
References
If you want a deeper understanding of HOCs, check out React's official docs.