I recently came across an interview question about Higher-Order Components (HOCs) and their role in enhancing a component's functionality. While HOCs are a powerful and advanced technique, it's worth noting that they're no longer as commonly used in modern React. In fact, the latest React documentation has phased out detailed explanations of HOCs.
In this blog post, I'll explore what HOCs are, their advantages, and why they are no longer the recommended approach in contemporary React development.
Higher-Order Component (HOC)
[A] higher-order component is a function that takes a component and returns a new component.
const EnhancedComponent = higherOrderComponent(WrappedComponent);
This example comes from the older React documentation. I've updated the example to use a functional component and summarized the explanation.
A CommentList
component subscribes to an external data source to render a list of comments:
import React, { useEffect, useState } from "react";
function CommentList() {
// "DataSource" is some global data source
const [comments, setComments] = useState(DataSource.getComments());
useEffect(() => {
function handleChange() {
setComments(DataSource.getcomments());
}
DataSource.addChangeListener(handleChange);
return () => {
DataSource.removeChangeListener(handleChange);
};
}, []);
return (
<div>
{comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
);
}
export default CommentList;
A BlogPost
Component subscribes to a single blog post:
import React, { useEffect, useState } from "react";
function BlogPost(props) {
const [blogPost, setBlogPost] = useState(DataSource.getBlogPost(props.id));
useEffect(() => {
function handleChange() {
setBlogPost(DataSource.getBlogPost(props.id))
}
DataSource.addChangeListener(handleChange)
return () => {
DataSource.removeChangeListener(handleChange)
}
}, [props.id]);
return <TextBlock text={blogPost} />
}
export default BlogPost;
DataSource
would look something like this:
const DataSource = {
getComments: () => {
return [...];
},
addChangeListener: (callback) => {},
removeChangeListener: (callback) => {}
};
export default DataSource;
CommentList
and BlogPost
are not identical, but much of their implementation is the same. To simplify this repetition, we can create a function that abstracts these shared patterns.
// Custom Hook
export function useSubscription(selectData, props) {
const [data, setData] = useState(selectData(DataSource, props));
useEffect(() => {
function handleChange() {
setData(selectData(DataSource, props))
}
DataSource.addChangeListener(handleChange)
return () => {
DataSource.removeChangeListener(handleChange)
}
}, [props])
return data
}
function withSubscription(WrappedComponent, selectData) {
return function(props) {
const data = useSubsctiption(selectData, props)
return <WrappedComponent data={data} {...props} />
}
}
When CommentListWithSubscription
and BlogPostWithSubscription
are rendered, they will pass a data prop containing the most current information from DataSource
to their respective components.
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
)
const BlogPostWithSubscription = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id)
)
A Higher-Order Component (HOC) is a pure function that enhances the original component by wrapping it in a container component, allowing us to share logic across multiple components without side effects.
"Higher-order components are not commonly used in modern React code," noted the legacy documentation.
After researching the reasons, developers have pointed out several disadvantages:
Complexity: HOCs can create deeply nested wrappers, making code harder to read and debug.
Prop Collisions: HOCs manipulate props, which can lead to unintended conflicts and issues.
Hooks as an Alternative
Custom hooks offer a more concise and straightforward way to handle the same logic, effectively replacing the need for HOCs.
Some developers still use HOCs for tasks like authentication or error handling. It's important to understand both the pros and cons and stay updated on the latest trends, allowing us to engage in informed discussions with our team members.
Top comments (0)