React Hooks, introduced in React 16.8, have changed the way developers write components. With Hooks, state and side effects can now be handled in functional components, making class components largely unnecessary in many cases.
This shift has sparked discussions: Are class components obsolete? Should we stop using them entirely?
The answer is: mostly, yes—but not always. In this post, we’ll explore the performance and readability improvements of functional components with Hooks and discuss the few cases where class components may still be relevant.
Performance and Readability Improvements
1. Less Boilerplate, More Readable Code
Class components come with extra syntax, including constructor
, this
, bind
, and lifecycle methods. This can make code more verbose and harder to read.
Class Component Example (Before Hooks)
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.increment = this.increment.bind(this);
}
increment() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
Now, let’s rewrite the same component using functional components and useState
:
Functional Component with Hooks (After Hooks)
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
What changed?
- No more
this
– No need to referencethis.state
or bind methods. - Fewer lines of code – The same functionality is written in a much simpler way.
- More readable and maintainable – Anyone reading this component can quickly understand how it works.
2. Improved Performance with Hooks
Functional components with Hooks can be more efficient because they avoid the overhead of class components. Some key improvements include:
- Faster initialization – No constructor or method binding.
- Better minification and optimization – Functional components are easier for compilers to optimize.
- Avoiding unnecessary re-renders – Hooks like
useMemo
anduseCallback
help optimize re-renders.
Class components rely on setState
, which merges state updates. Functional components, however, allow more fine-grained control over state updates using Hooks like useReducer
.
3. Better Reusability with Custom Hooks
Hooks allow you to reuse logic in ways that class components never could. Before Hooks, we had to rely on:
- Higher-Order Components (HOCs) – Wrapping components in another component to share logic.
- Render Props – Passing functions as props to reuse behavior.
Both of these patterns added extra complexity. Hooks simplify everything by allowing custom Hooks to encapsulate logic.
Example: Custom Hook for Window Width
import { useState, useEffect } from "react";
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return width;
}
function Component() {
const width = useWindowWidth();
return <p>Window width: {width}px</p>;
}
Instead of writing the same componentDidMount
and componentWillUnmount
logic in multiple class components, this logic is now reusable across multiple components using Hooks.
When Should You Still Use Class Components?
Despite all these benefits, class components are not completely obsolete (at least in 2019). Here are some situations where they may still be needed:
1. Legacy Codebases
If you’re working on a React project that predates Hooks (pre-2019), refactoring hundreds of class components might not be practical. Many teams will continue maintaining class-based components for compatibility.
2. Error Boundaries
Currently, Hooks do not support error boundaries. Error boundaries must still be implemented using class components:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log("Error caught:", error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
3. Certain Third-Party Libraries
Some older third-party libraries may still rely on class components. While many have added Hooks support, some require class-based lifecycle methods.
4. Rare Performance Optimizations
In very specific cases, class components can offer better optimization techniques, like shouldComponentUpdate and PureComponent, though Hooks now provide alternatives like React.memo
and useMemo
.
Conclusion
React Hooks have revolutionized how we write React components. By moving away from class components, we get:
- Cleaner, more readable code
- Better performance and optimization
- Easier logic reuse with custom Hooks
However, class components still have a small place in React development, especially for legacy support and error boundaries.
Should You Stop Using Class Components?
- If you’re starting a new project in 2019 → Use functional components with Hooks.
- If you’re maintaining an existing class-based project → You don’t need to refactor everything immediately.
- If you need error boundaries → You still have to use class components (for now).
As React continues to evolve, it’s likely that class components will become increasingly rare, but for now, they still serve a purpose in certain situations.
If you’re new to Hooks, consider exploring:
- useState for managing local state
- useEffect for handling side effects
- useReducer for complex state logic
Functional components with Hooks are the future of React—and the future is already here.