React: Functional vs Class Components
In 2019, React version 16.8 introduced Hooks, fundamentally shifting the React ecosystem away from Object-Oriented Class components toward pure Functional components.
What is the difference between Functional and Class components, and why did the industry shift towards functional ones?
While you will almost exclusively write Functional components today, interviewers still ask this to see if you understand React's evolution and how to maintain legacy codebases.
1. Syntax and Boilerplate
Class Components
Class components require extending React.Component, defining a render() method, and managing the notoriously confusing this keyword.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
// You had to manually bind event handlers!
this.increment = this.increment.bind(this);
}
increment() {
this.setState({ count: this.state.count + 1 });
}
render() {
return <button onClick={this.increment}>{this.state.count}</button>;
}
}Functional Components
Functional components are simply JavaScript functions that accept props as an argument and return JSX. State is managed elegantly via the useState hook.
function Counter() {
const [count, setCount] = useState(0);
// No 'this' binding needed!
const increment = () => setCount(count + 1);
return <button onClick={increment}>{count}</button>;
}2. Managing the Lifecycle
Before Hooks, Functional components were "dumb" or "stateless"—they could only accept props and render UI. If you needed to fetch data on mount, you had to use a Class component to access lifecycle methods.
Class Lifecycle Methods
Class components force you to split related logic across multiple disconnected methods based on time.
class UserProfile extends React.Component {
componentDidMount() {
// 1. Subscribe to chat
// 2. Fetch user data
}
componentWillUnmount() {
// 1. Unsubscribe from chat
}
}Functional useEffect Hook
Hooks allow you to group related logic by concern rather than by time. A single useEffect handles mounting, updating, and unmounting (cleanup) in one cohesive block.
function UserProfile() {
useEffect(() => {
// 1. Subscribe to chat
return () => {
// 2. Unsubscribe from chat (Cleanup runs on unmount)
};
}, []); // Empty array simulates componentDidMount
}3. Reusability (The True Reason for the Shift)
The biggest flaw of Class components was how difficult it was to share non-visual stateful logic between components. Developers had to use convoluted patterns like Higher-Order Components (HOCs) or Render Props, which lead to "Wrapper Hell" (deeply nested component trees just to inject state).
Functional components solved this brilliantly with Custom Hooks. You can extract stateful logic into a reusable function (e.g., useWindowSize or useAuth) and seamlessly drop it into any component without altering the component hierarchy.
Senior-Level Interview Answer
The transition from Class to Functional components marked a paradigm shift in React from Object-Oriented inheritance to functional composition. Class components suffer from verbose boilerplate, complex
thisbinding mechanics, and rigid lifecycle methods (componentDidMount,componentDidUpdate) that force developers to split logically related code across disparate methods. The introduction of Hooks empowered functional components to manage state and side effects concisely. Most importantly, Custom Hooks resolved the architectural limitations of class-based code sharing (which relied on cumbersome HOCs and render props), allowing developers to extract and reuse stateful logic frictionlessly without polluting the component tree.
Common Interview Mistakes
❌ Claiming Functional Components are massively faster
While Functional components are slightly more lightweight because they don't require instantiating an object instance, the performance difference in the rendering phase is historically negligible. The primary advantages are developer experience, code minification (functions minify better than classes), and clean architectural composition, not raw execution speed.
