Functional Components vs Class Components

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

Functional Components vs Class Components

Historically, React provided two ways to define components: Class Components and Functional Components. Since the introduction of Hooks in React 16.8 (2019), Functional Components have become the standard for writing modern React applications.

Class Components (Legacy)

Class components are ES6 classes that extend from React.Component. They require a render() method to return JSX and use the this keyword heavily for state (this.state) and props (this.props).

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    // Event handlers often needed binding
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.props.label}: {this.state.count}
      </button>
    );
  }
}

Drawbacks of Class Components:

  • The this keyword can be confusing and leads to bugs if not bound correctly.
  • Lifecycle methods (componentDidMount, componentDidUpdate, etc.) force you to split related logic across multiple methods.
  • Reusing stateful logic across components (via Higher Order Components or Render Props) resulted in deeply nested “wrapper hell”.

Functional Components (Modern)

Functional components are plain JavaScript functions. With the addition of Hooks, they can manage state, side effects, and context—doing everything classes can do, but with significantly less boilerplate and better code organization.

import { useState } from 'react';

function Counter({ label }) {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      {label}: {count}
    </button>
  );
}

Why the Shift?

  1. Less Boilerplate: No constructors, no super(props), no this.bind.
  2. Better Minification: Classes minify poorly compared to functions.
  3. Logic Reuse: Custom hooks allow you to extract and reuse stateful logic easily, avoiding wrapper hell.
  4. Mental Model: Functions align better with React’s core philosophy: UI = f(state).

While class components are still supported for backwards compatibility, the React team strongly recommends writing all new code using functional components and hooks.

Interview Questions

Q: Why did React strongly pivot from Class components to Functional components?
A: With the introduction of Hooks in React 16.8, functional components gained the ability to manage state and side effects. Functional components are preferred because they eliminate the confusion of this binding, significantly reduce boilerplate, and allow stateful logic to be easily extracted and reused via Custom Hooks.

Q: Do Functional components have lifecycle methods?
A: No. Functional components do not have componentDidMount or componentWillUnmount. Instead, they use the useEffect hook to synchronize with external systems. A single useEffect can handle mounting, updating, and unmounting logic together.