Component Functional

Use function components and Hooks exclusively; avoid class components in new code.

Why?  Aligns with the current React runtime and future features (concurrency, RSC).

React’s modern features—Concurrent Rendering, Suspense, React Server Components—are designed around function components + Hooks. Class components still work, but they lock you out of new APIs and add boilerplate (binding, lifecycles, this issues). Teams often keep reaching for classes out of habit or to copy old tutorials, only to discover that mixing paradigms complicates state management and hurts upgrade paths.

Correct Example

// Counter.tsx — idiomatic Hook‑based component
import { useState, useEffect } from "react";

export default function Counter({ step = 1 }: { step?: number }) {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`; // side‑effect in a Hook
  }, [count]);

  return (
    <button
      onClick={() => setCount((c) => c + step)}
      className="rounded-xl bg-blue-600 px-4 py-2 font-medium text-white"
    >
      Clicked {count} times
    </button>
  );
}

What’s happening?

  • State (useState) and side‑effects (useEffect) live in a plain function—no this, no bindings.
  • Works seamlessly with React’s future‑proof rendering modes.

Incorrect Example

// CounterClass.tsx — legacy approach
import { Component } from "react";

interface Props {
  step?: number;
}
interface State {
  count: number;
}

export default class CounterClass extends Component<Props, State> {
  state: State = { count: 0 };

  componentDidMount() {
    document.title = `Count: ${this.state.count}`;
  }
  componentDidUpdate() {
    document.title = `Count: ${this.state.count}`;
  }

  handleClick = () => {
    this.setState((prev) => ({ count: prev.count + (this.props.step ?? 1) }));
  };

  render() {
    const { count } = this.state;
    return (
      <button
        onClick={this.handleClick}
        className="rounded-xl bg-blue-600 px-4 py-2 font-medium text-white"
      >
        Clicked {count} times
      </button>
    );
  }
}
// Extra boilerplate, harder to compose with modern features, and incompatible
// with React Server Components or certain concurrent patterns.

Key Takeaways

  • Future‑proof by default: Function components are required for Suspense for Data Fetching, RSC, and new Hook‑based APIs.
  • Less boilerplate: No this, lifecycle method maze, or manual bindings—just plain JavaScript functions.
  • Easier composition: Custom Hooks let you share logic without HOCs or render props.
  • Gradual adoption: If you still have class components, wrap new work in functions and migrate the old code incrementally.