DEV Community

Tpoint Tech
Tpoint Tech

Posted on

Higher-Order Components in React: Concept & Examples

Introduction

In React, a Higher-Order Component (HOC) is an advanced technique for reusing component logic. It is not a component itself, but a function that takes a component and returns a new component. Essentially, it allows you to enhance or modify a component’s behaviour without changing its original code.
React is the most commonly used part of the front-end library that uses the virtual DOM. If the developers create a large application, they use the higher-order component because it can remove the duplication of your code. By the use of this component, you can make your code more scalable, maintainable, and reusable.
In this article, we will explore higher-order components in React with practical examples.

Higher-Order Components in React:

It is also referred to as a pure function. This is an advanced concept of React that takes a component and gives an enhanced component with some capabilities. You cannot directly update via the input component; it returns only a new component. This helps to manage the component logic for one or more components.

Syntax:

const data = (WrappedComponent) => {
return function EnhancedComponent(props) {
// Write your code here
return <WrappedComponent {...props} extraProp="value" />;
};
};

Example
Code:
import React from "react";
const data = (WrappedComponent) => {
return function data({ isLoading, ...props }) {
if (isLoading) {
return <p>Loading...</p>;
}
return <WrappedComponent {...props} />;
};
};
const UserList = ({ users }) => {
return (
<ul>
{users.map((user, index) => (
<li key={index}>{user}</li>
))}
</ul>
);
};
const UserListWithLoading = data(UserList);
function App() {
const users = ["John", "Jane", "Alex"];
return <UserListWithLoading isLoading={false} users={users} />;
}
export default App;

Output:
• John
• Jane
• Alex

Why use Higher-Order Components in React?

Here are some of the reasons mentioned below:

1) Code reusability:
Instead of writing the same logic multiple times in different components, Higher-Order Components (HOCs) allow you to write it once and reuse it everywhere.

2) Cleaner Code:
This component can be easily built into your React code, making it easier to read and modularize. It follows the DRY concepts.

3) Flexibility:
This component takes the parameters and allows management the functionality of the higher-order component.

4) Conditional Rendering:
It can show only these components that fulfil the condition. Without this component, you can write more conditional statements in the component.

5) Better Maintenance:
Higher-order components provide features that allow you to modify the logic once and automatically modify all the components.

When to Use Higher-Order Components in React?

Higher-Order Components are a powerful pattern, but they are not needed in every situation. You should consider using HOCs when you want to reuse component logic or enhance behaviour without duplicating code. Here are the most common scenarios:

1) Scalable Applications:
It enables you to handle the logic across multiple components easily. This builds up your application to be more scalable, readable, and removes duplicate code.

2) Authentication:
With the use of the withAuth() function, you can verify that the user successfully signed up or logged in, and also render if the credentials are not correct.

3) Fetching Data from API:
This component is used for handling the data through the API and modifying the data via props.

Practical Examples of Higher-Order Components in React:

1) Data fetching:
Example
Code:

import React from "react";
const withAuth = (WrappedComponent) => {
return function AuthComponent(props) {
const isAuth = localStorage.getItem("token");
if (!isAuth) {
return <p>Please login to access this page.</p>;
}
return <WrappedComponent {...props} />;
};
};
const Main = () => {
return (
<div>
<h2>Welcome to the Dashboard!</h2>
<p>You can see SEO content here.</p>
</div>
);
};
const DashboardWithAuth = withAuth(Main);
function App() {
return <DashboardWithAuth />;
}
export default App;

Output:
Please login to access this page.

2) User Authentication:
Example
Code:

import React, { useState } from "react";
const withLogger = (WrappedComponent) => {
return function LoggerComponent(props) {
const [logs, setLogs] = useState([]);
const addLog = (message) => {
const timestamp = new Date().toLocaleTimeString();
setLogs((prevLogs) => [...prevLogs,
${timestamp}: ${message}]);
};
return (
<div style={{ border: "2px solid #ccc", padding: "20px", margin: "20px" }}>
<WrappedComponent {...props} addLog={addLog} />
<div style={{ marginTop: "20px" }}>
<h3>Action Logs:</h3>
<ul>
{logs.map((log, index) => (
<li key={index}>{log}</li>
))}
</ul>
</div>
</div>
);
};
};
const ButtonComponent = ({ addLog }) => {
return (
<button
onClick={() => addLog("Button clicked!")}
style={{ padding: "10px 20px", fontSize: "16px" }}
>
Click Me
</button>
);
};
const InputComponent = ({ addLog }) => {
const [value, setValue] = useState("");
return (
<div>
<input
type="text"
placeholder="Type something..."
value={value}
onChange={(e) => {
setValue(e.target.value);
addLog(
Input changed to: ${e.target.value});
}}
style={{ padding: "5px", fontSize: "16px" }}
/>
</div>
);
};
const ButtonWithLogger = withLogger(ButtonComponent);
const InputWithLogger = withLogger(InputComponent);
function App() {
return (
<div style={{ textAlign: "center" }}>
<h1>React HOC Logging Example</h1>
<ButtonWithLogger />
<InputWithLogger />
</div>
);
}
export default App;

Output:

3) Finds Error Boundary:
Example
Code:
import React from "react";
const err = (WrappedComponent) => {
return class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error("Error:", error, info);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return <WrappedComponent {...this.props} />;
}
};
};
const bugs = () => {
throw new Error("I crashed!");
return <div>All good!</div>;
};
export default err(bugs);

Output:
Something went wrong.

Best Practices of Higher-Order Component:

1) Immutability:
With the use of this component, you cannot directly update the component through the props. Because it returns a new enhanced component.

2) Handle the props:
You can pass the props through the wrapped component by using the spread operator, such as ({…props}).

3) Avoid Overuse:
If you are using this component many times, it can make your code more difficult and complex. Therefore, you should use this component only when there is a need.

Conclusion:

This article gives you a deep explanation of Higher-Order components in React from beginner to professional-level developers. This component is one of the most useful concepts for enhancing component and component logic without updating the component. It allows developers to perform operations like data fetching, user signup, or login, and authorization etc.

You can easily learn ReactJS effectively through the Tpoint tech website, as it provides tutorials, interview questions, and a detailed explanation of all concepts.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.