While working on a React project for a U.S.-based analytics dashboard, I needed to reuse a few UI components with slightly different behaviors.
At first, I thought of duplicating the component and tweaking it, but that quickly became messy. That’s when I explored ways to extend functional components in ReactJS, and it made my workflow much cleaner.
In this tutorial, I’ll show you how I extend functional components in React using composition, higher-order components (HOCs), and custom hooks. These methods help you write cleaner, reusable, and maintainable React code.
What Does It Mean to Extend a Functional Component?
In React, “extending” a component doesn’t mean inheritance (like in class-based components). Instead, it means reusing and enhancing an existing component’s logic or UI without rewriting it.
Functional components rely on composition; you build complex UIs by combining smaller, reusable pieces.
For example, you might want to:
- Add logging or analytics to an existing component.
- Reuse a button with different colors and behaviors.
- Wrap a component to handle API loading states.
Let’s look at a few practical methods I use.
Method 1 – Extend Functional Components Using Composition
Composition is the most common and React-friendly way to extend functionality. It involves wrapping components inside others.
Here’s a simple example I used in my project to extend a Card component.
Example: Base Card Component
// Card.js
import React from 'react';
const Card = ({ title, children }) => {
return (
<div style={{
border: '1px solid #ccc',
borderRadius: '8px',
padding: '16px',
margin: '10px',
boxShadow: '0 2px 5px rgba(0,0,0,0.1)'
}}>
<h3>{title}</h3>
<div>{children}</div>
</div>
);
};
export default Card;You can refer to the screenshot below to see the output

Example: Extended Card with Footer
Now let’s extend this Card to include a footer message.
// InfoCard.js
import React from 'react';
import Card from './Card';
const InfoCard = ({ title, children, footer }) => {
return (
<Card title={title}>
{children}
{footer && (
<div style={{ marginTop: '10px', fontSize: '0.9em', color: '#555' }}>
{footer}
</div>
)}
</Card>
);
};
export default InfoCard;Method 2 – Extend Functional Components Using Higher-Order Components (HOCs)
A Higher-Order Component (HOC) is a function that takes a component and returns a new one. It’s great for adding common logic like authentication, logging, or analytics.
Here’s how I used an HOC to add logging to multiple components.
Example: HOC for Logging
// withLogger.js
import React, { useEffect } from 'react';
const withLogger = (WrappedComponent, componentName) => {
return (props) => {
useEffect(() => {
console.log(`${componentName} mounted`);
return () => console.log(`${componentName} unmounted`);
}, []);
return <WrappedComponent {...props} />;
};
};
export default withLogger;Example: Using the HOC
// Dashboard.js
import React from 'react';
import withLogger from './withLogger';
const Dashboard = () => {
return <h2>Welcome to the Analytics Dashboard</h2>;
};
export default withLogger(Dashboard, 'Dashboard');You can refer to the screenshot below to see the output

When the Dashboard component mounts or unmounts, it logs messages to the console. You can reuse withLogger across multiple components without repeating code.
Method 3 – Extend Functional Components Using Custom Hooks
Custom hooks are another great way to extend functionality, especially logic-based features like fetching data, handling forms, or managing local storage.
Here’s how I extended a component to handle API calls using a custom hook.
Example: Custom Hook for Fetching Data
// useFetch.js
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch(() => setLoading(false));
}, [url]);
return { data, loading };
};
export default useFetch;Example: Use the Custom Hook
// UsersList.js
import React from 'react';
import useFetch from './useFetch';
const UsersList = () => {
const { data, loading } = useFetch('https://jsonplaceholder.typicode.com/users');
if (loading) return <p>Loading users...</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name} — {user.email}</li>
))}
</ul>
);
};
export default UsersList;You can refer to the screenshot below to see the output

The useFetch hook can now be used in any component that needs data fetching, making your code more modular and testable.
Method 4 – Extend Functional Components with Props
Sometimes, the simplest way to “extend” a component is just to pass additional props that modify its behavior.
Example: Configurable Button Component
// Button.js
import React from 'react';
const Button = ({ label, color = 'blue', onClick }) => {
return (
<button
onClick={onClick}
style={{
backgroundColor: color,
color: 'white',
padding: '10px 16px',
border: 'none',
borderRadius: '5px',
cursor: 'pointer'
}}
>
{label}
</button>
);
};
export default Button;Usage Example
// App.js
import React from 'react';
import Button from './Button';
function App() {
return (
<div style={{ padding: '20px' }}>
<Button label="Save Report" color="green" onClick={() => alert('Report saved!')} />
<Button label="Delete Report" color="red" onClick={() => alert('Report deleted!')} />
</div>
);
}
export default App;This approach keeps one core component (Button) flexible enough to handle multiple use cases through props, no duplication needed.
Best Practices When Extending Functional Components
Here are some lessons I’ve learned over the years:
- Prefer composition over inheritance. React’s design philosophy encourages composition.
- Use HOCs and hooks for logic reuse. Keep UI and logic separate.
- Keep components small and focused. Each should do one thing well.
- Avoid prop drilling. Use context or hooks to share state across components.
When I first started extending functional components, I tried to mimic class inheritance. It worked, but the code was hard to maintain. Once I switched to composition and hooks, everything became cleaner and easier to debug.
These techniques not only make your React apps more scalable but also align with modern React best practices.
You may read:
- How to Handle React Component Unmount
- Fetch and Display Data from an API in React
- Route Component in React Router
- Optional Props in React Components

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.