Class Components

Loading

Class components were the original way to create stateful components in React before the introduction of hooks. While functional components with hooks are now preferred, understanding class components remains important for maintaining legacy code.

1. What Are Class Components?

Class components are ES6 classes that:

  • Extend React.Component
  • Have a render() method that returns JSX
  • Can maintain internal state
  • Have access to lifecycle methods
import React from 'react';

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

2. Key Features of Class Components

Props

class UserProfile extends React.Component {
  render() {
    const { name, age, isAdmin } = this.props;
    return (
      <div>
        <h2>{name}</h2>
        <p>Age: {age}</p>
        {isAdmin && <button>Edit Profile</button>}
      </div>
    );
  }
}

State Management

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

Lifecycle Methods

class DataFetcher extends React.Component {
  state = { data: null };

  componentDidMount() {
    fetch(`/api/users/${this.props.userId}`)
      .then(res => res.json())
      .then(data => this.setState({ data }));
  }

  componentDidUpdate(prevProps) {
    if (this.props.userId !== prevProps.userId) {
      this.fetchData();
    }
  }

  componentWillUnmount() {
    // Clean up any subscriptions
  }

  render() {
    return <div>{this.state.data ? this.state.data.name : 'Loading...'}</div>;
  }
}

3. Complete Lifecycle Overview

Mounting Phase

  1. constructor()
  2. static getDerivedStateFromProps()
  3. render()
  4. componentDidMount()

Updating Phase

  1. static getDerivedStateFromProps()
  2. shouldComponentUpdate()
  3. render()
  4. getSnapshotBeforeUpdate()
  5. componentDidUpdate()

Unmounting Phase

  1. componentWillUnmount()

Error Handling

  1. static getDerivedStateFromError()
  2. componentDidCatch()

4. When to Use Class Components Today

While functional components are preferred, class components are still necessary for:

  • Error boundaries (no hook equivalent exists)
  • Legacy codebases that haven’t migrated to hooks
  • Certain third-party libraries that expect class components

5. Converting Class Components to Functional Components

Class Component

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { todos: [], input: '' };
  }

  componentDidMount() {
    const saved = localStorage.getItem('todos');
    if (saved) this.setState({ todos: JSON.parse(saved) });
  }

  componentDidUpdate() {
    localStorage.setItem('todos', JSON.stringify(this.state.todos));
  }

  addTodo = () => {
    if (this.state.input.trim()) {
      this.setState({
        todos: [...this.state.todos, { text: this.state.input, completed: false }],
        input: ''
      });
    }
  };

  render() {
    return (
      <div>
        <input
          value={this.state.input}
          onChange={e => this.setState({ input: e.target.value })}
          placeholder="Add todo..."
        />
        <button onClick={this.addTodo}>Add</button>
        <ul>
          {this.state.todos.map((todo, i) => (
            <li key={i}>{todo.text}</li>
          ))}
        </ul>
      </div>
    );
  }
}

Equivalent Functional Component

function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  useEffect(() => {
    const saved = localStorage.getItem('todos');
    if (saved) setTodos(JSON.parse(saved));
  }, []);

  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, { text: input, completed: false }]);
      setInput('');
    }
  };

  return (
    <div>
      <input
        value={input}
        onChange={e => setInput(e.target.value)}
        placeholder="Add todo..."
      />
      <button onClick={addTodo}>Add</button>
      <ul>
        {todos.map((todo, i) => (
          <li key={i}>{todo.text}</li>
        ))}
      </ul>
    </div>
  );
}

6. Key Differences from Functional Components

FeatureClass ComponentsFunctional Components
SyntaxES6 classJavaScript function
Statethis.state and setState()useState hook
LifecycleMethods like componentDidMountuseEffect hook
this bindingRequires binding or arrow functionsNot needed
PerformanceSlightly heavierSlightly lighter
ReusabilityMixins (deprecated)Custom hooks

7. Best Practices for Class Components

  1. Bind event handlers in constructor or use arrow functions
  2. Use shouldComponentUpdate for performance optimizations
  3. Clean up resources in componentWillUnmount
  4. Avoid setState in render (causes infinite loops)
  5. Consider migrating to functional components for new code

Leave a Reply

Your email address will not be published. Required fields are marked *