Introduction
React offers two primary ways of defining components: functional components and class components. While functional components have become the modern standard after the introduction of Hooks in React 16.8, class components still hold significant importance. Many existing projects are built with class components, and understanding them is crucial for developers who may need to maintain legacy codebases, work with older libraries, or fully grasp React’s evolution.
In this post, we will explore class components in detail: their structure, how they work, lifecycle methods, handling state, props, event handling, and best practices. By the end, you will have a solid understanding of how to create and use class components in React.
What are Class Components?
Class components in React are ES6 classes that extend from React.Component. They must include a render() method that returns JSX, which defines the UI.
Key Features of Class Components
- Defined as ES6 classes.
- Must extend
React.ComponentorReact.PureComponent. - Require a
render()method that outputs JSX. - Have access to state (internal data).
- Can use lifecycle methods like
componentDidMount,componentDidUpdate, etc.
Basic Structure of a Class Component
Let’s look at the simplest class component in React:
import React from 'react';
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
export default Welcome;
Explanation
class Welcome extends React.Componentdefines a new class that inherits fromReact.Component.render()is required and returns the JSX UI.this.propsis used to access props passed from the parent.
Class Component vs Functional Component
Functional Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Class Component
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Both achieve the same result, but the class component gives access to additional features such as state and lifecycle methods (without Hooks).
Props in Class Components
Props in class components work the same way as in functional components, but they are accessed using this.props.
Example
class Greeting extends React.Component {
render() {
return <h2>Good Morning, {this.props.username}!</h2>;
}
}
function App() {
return (
<div>
<Greeting username="Alice" />
<Greeting username="Bob" />
</div>
);
}
Output
Good Morning, Alice!
Good Morning, Bob!
State in Class Components
State is one of the most powerful features in class components. Unlike props, which are immutable, state is local to the component and can change over time.
Declaring State
In class components, state is initialized inside the constructor.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <h1>Count: {this.state.count}</h1>;
}
}
Updating State
You should never modify state directly. Instead, use this.setState().
Example
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>Count: {this.state.count}</h1>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
Each time the button is clicked, the state updates and the component re-renders.
Handling Events in Class Components
Event handling in class components requires binding methods to the component’s context (this). Without binding, this would be undefined inside the event handler.
Example without Binding (Error)
class ButtonDemo extends React.Component {
constructor(props) {
super(props);
this.state = { message: "Click the button" };
}
handleClick() {
this.setState({ message: "Button Clicked!" });
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.handleClick}>Click Me</button>
</div>
);
}
}
This code will throw an error because this is not bound.
Correct Approach – Binding in Constructor
class ButtonDemo extends React.Component {
constructor(props) {
super(props);
this.state = { message: "Click the button" };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ message: "Button Clicked!" });
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.handleClick}>Click Me</button>
</div>
);
}
}
Alternative Approach – Arrow Functions
Using arrow functions automatically binds this.
class ButtonDemo extends React.Component {
state = { message: "Click the button" };
handleClick = () => {
this.setState({ message: "Button Clicked!" });
};
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.handleClick}>Click Me</button>
</div>
);
}
}
Lifecycle Methods
One of the key reasons class components are important is lifecycle methods. These methods allow you to hook into different phases of a component’s life.
Three Main Phases
- Mounting – When the component is inserted into the DOM.
- Updating – When state or props change.
- Unmounting – When the component is removed.
Common Lifecycle Methods
constructor()– Initializes state.componentDidMount()– Runs after the component mounts.componentDidUpdate()– Runs after updates.componentWillUnmount()– Runs before unmounting.
Example: Using Lifecycle Methods
class LifecycleDemo extends React.Component {
constructor(props) {
super(props);
this.state = { message: "Hello World!" };
console.log("Constructor called");
}
componentDidMount() {
console.log("Component Mounted");
}
componentDidUpdate() {
console.log("Component Updated");
}
componentWillUnmount() {
console.log("Component Will Unmount");
}
changeMessage = () => {
this.setState({ message: "Message Updated!" });
};
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.changeMessage}>Change</button>
</div>
);
}
}
When rendered, this component logs messages during its lifecycle.
Conditional Rendering in Class Components
Conditional rendering decides what UI to show based on state or props.
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.state = { isLoggedIn: false };
}
toggleLogin = () => {
this.setState({ isLoggedIn: !this.state.isLoggedIn });
};
render() {
return (
<div>
{this.state.isLoggedIn ? <h1>Welcome Back!</h1> : <h1>Please Login</h1>}
<button onClick={this.toggleLogin}>
{this.state.isLoggedIn ? "Logout" : "Login"}
</button>
</div>
);
}
}
Rendering Lists in Class Components
class ListDemo extends React.Component {
render() {
const items = ["Apple", "Banana", "Cherry"];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
}
Real-World Example – Todo App with Class Components
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.state = { todos: [], input: "" };
}
handleChange = (e) => {
this.setState({ input: e.target.value });
};
addTodo = () => {
if (this.state.input.trim() !== "") {
this.setState((prevState) => ({
todos: [...prevState.todos, prevState.input],
input: "",
}));
}
};
render() {
return (
<div>
<h1>Todo List</h1>
<input
type="text"
value={this.state.input}
onChange={this.handleChange}
/>
<button onClick={this.addTodo}>Add</button>
<ul>
{this.state.todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
}
}
This example demonstrates props, state, event handling, and rendering lists inside a class component.
Best Practices for Class Components
- Use functional components with Hooks for new projects but know class components for legacy support.
- Keep components small and focused on a single task.
- Always bind event handlers or use arrow functions.
- Use setState correctly and avoid direct state mutations.
- Use lifecycle methods for data fetching, subscriptions, and cleanup.
- Split complex UI into child components for reusability.
When to Use Class Components Today
Even though functional components dominate modern React development, class components are still useful in situations such as:
- Working with older React codebases.
- Understanding lifecycle methods for interviews and legacy projects.
- Reading React documentation before Hooks were introduced.
- Using some third-party libraries that rely on class components.
Leave a Reply