In modern React (versions 16.8 and later), the primary and practically only scenario where a class component is strictly preferred is when you need to create an Error Boundary. Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed . They are essential for preventing a single JavaScript error from unmounting your entire application and providing a graceful degradation experience for users.
The reason for this is technical: React's implementation of error boundaries relies on the class-based lifecycle methods static getDerivedStateFromError() and componentDidCatch(). As of React 19, there is no Hook-based equivalent for these specific methods . To implement this critical error-handling functionality, you must write a class component. This is often cited as the only class component a modern React developer might need to write .
Placement matters: An error boundary placed at the root of your app (<App>) provides a catch-all, but can be too coarse. Placing boundaries around specific, potentially error-prone components (like a widget or a comment section) allows the rest of the page to remain functional .
What they don't catch: Error boundaries do not catch errors inside event handlers, asynchronous code (e.g., setTimeout or fetch callbacks), server-side rendering, or errors thrown in the error boundary itself . For event handlers, you still need to use standard JavaScript try/catch blocks.
Function Components are still the standard: For everything else—managing state, side effects, context, performance optimizations, and building UI—function components with Hooks (useState, useEffect, useContext, etc.) are the recommended and more concise approach in modern React .
While there are theoretical scenarios where a class component could be preferred—for example, when working with a very large legacy codebase where a full migration is impractical, or when a team lacks familiarity with Hooks—these are not technical preferences but rather project-specific constraints. From a pure React best practices standpoint, function components with Hooks have effectively superseded class components for all use cases except the creation of Error Boundaries .