A higher order component is essentially a component that has been passed into a function. This function will return a new version of that component with some added functionality.
As a very simple example, let's say you want to fetch some data from API endpoints and display the data in multiple components throughout your app. Instead of writing the same setState(), componentDidMount(), fetch(), etc. in each class component, you could instead write a single function will return a component with these traits when you pass each component in as an argument.
import React from "react";
//the function that takes in a component
// and returns a higher order component that fetches the data from the API
// dataSource in this case would be the API endpoint, which is also passed in
const withData = (component, dataSource) => {
class WithData extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
fetch(dataSource)
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
}
return WithData;
};
So, now your UI component can be a functional component instead of a class component. Let's say we wanted to display a user and then list all of their posts below. It could be written as below.
import React from "react";
import withData from "../../with-data";
const UserProfile = ({ name, data, email }) => (
<div className="container">
<h1>{name}</h1>
<h2>{email}</h2>
Posts:
{data.map(post => (
<div className="post" key={post.id}>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
))}
</div>
);
// export this component by passing it into the function we just wrote,
// along with the dataSource (the API endpoint in this case)
//which will return the wrapped component with the fetch call to the API
//and the data in state, along with any other props (which were spread in using { ...this.props })
export default withData(
UserProfile,
"https://jsonplaceholder.typicode.com/posts"
);
You could now write other components that perform a similar role in your app as simple functional components as well. If you wanted to fetch and display a list of all users, you could write it in a very similar way, and just pass in the appropriate API endpoint when exporting the component.
import React from "react";
import withData from "../../with-data";
const UserList = ({ data }) => (
<div className="container user-list">
<h1> Users List </h1>
{data.map(user => (
<div className="post" key={user.id}>
<h1>{user.name}</h1>
<h2>{user.email}</h2>
</div>
))}
</div>
);
// Now all you have to do is pass in the correct endpoint and the HOC will fetch your users
export default withData(UserList, "https://jsonplaceholder.typicode.com/users");
Another option would be to pass the data into the components as props instead of as an argument in the function that returns a HOC.
So, instead of this:
export default withData(UserList, "https://jsonplaceholder.typicode.com/users");
You could just pass in the component export default withData(UserList);
and then wherever the component is rendered, you pass in the endpoint as one of the props:
// all your other code
render() {
return(
<UserProfile name='Mikkel' email='mikkel250@gmail.com' />
<UserList dataSource={"https://jsonplaceholder.typicode.com/users"} />
)};
Some React libraries use this pattern, such as connect() from Redux.
Top comments (0)