Higher-order components (HoC) in React
Higher-order components (HOCs) are a pattern in React for reusing component logic. They are functions that take a component and return a new component with enhanced behavior or additional props. HOCs are useful in several scenarios, particularly when you need to apply the same logic to multiple components.
Here are some common use cases for higher-order components in React:
1. Code Reuse and Logic Abstraction
HOCs allow you to extract and reuse logic across multiple components. This can be particularly useful for things like fetching data, handling authentication, or managing state.
Example: Fetching Data
import React, { useState, useEffect } from 'react';
const withDataFetching = (url) => (WrappedComponent) => {
return (props) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, [url]);
return <WrappedComponent data={data} loading={loading} {...props} />;
};
};
const UserList = ({ data, loading }) => {
if (loading) return <div>Loading...</div>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
const UsersWithFetching = withDataFetching('https://jsonplaceholder.typicode.com/users')(UserList);
const App = () => <UsersWithFetching />;
export default App;
2. Accessing Context
HOCs can be used to provide access to context data, making it easier to share context across multiple components without prop drilling.
Example: Accessing Theme Context
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
const withTheme = (WrappedComponent) => (props) => {
const theme = useContext(ThemeContext);
return <WrappedComponent theme={theme} {...props} />;
};
const ThemedButton = ({ theme }) => {
return <button className={theme}>Themed Button</button>;
};
const ThemedButtonWithTheme = withTheme(ThemedButton);
const App = () => (
<ThemeContext.Provider value="dark">
<ThemedButtonWithTheme />
</ThemeContext.Provider>
);
export default App;
3. Conditional Rendering
HOCs can conditionally render components based on certain conditions, such as user authentication status or feature flags.
Example: Authentication Check
import React from 'react';
const withAuthentication = (WrappedComponent) => (props) => {
const isAuthenticated = // your logic to check authentication
return isAuthenticated ? <WrappedComponent {...props} /> : <div>Please log in</div>;
};
const Dashboard = () => {
return <div>Dashboard</div>;
};
const DashboardWithAuth = withAuthentication(Dashboard);
const App = () => <DashboardWithAuth />;
export default App;
4. Modifying Props
HOCs can modify the props that are passed to a component. This can be useful for things like adding default props or transforming the data before it reaches the component.
Example: Adding Default Props
import React from 'react';
const withDefaultProps = (defaultProps) => (WrappedComponent) => (props) => {
return <WrappedComponent {...defaultProps} {...props} />;
};
const Button = ({ color, children }) => {
return <button style={{ backgroundColor: color }}>{children}</button>;
};
const ButtonWithDefaults = withDefaultProps({ color: 'blue' })(Button);
const App = () => <ButtonWithDefaults>Click Me</ButtonWithDefaults>;
export default App;
5. Performance Optimization
HOCs can be used to optimize performance by preventing unnecessary re-renders using techniques like memoization or shouldComponentUpdate logic.
Example: Memoization
import React, { memo } from 'react';
const withMemo = (WrappedComponent) => {
return memo(WrappedComponent);
};
const ExpensiveComponent = ({ data }) => {
// expensive rendering logic
return <div>{data}</div>;
};
const MemoizedComponent = withMemo(ExpensiveComponent);
const App = () => <MemoizedComponent data="Hello World" />;
export default App;