Introduction
React class components, before the introduction of functional components with hooks, were the primary way to build complex React applications. Class components have a unique feature called lifecycle methods that allow developers to run code at specific points in a component’s life. These lifecycle methods provide hooks into different stages of a component’s existence, such as when it is created, updated, or destroyed.
Understanding lifecycle methods is essential for developers who maintain or work with React codebases written in class components. Even though functional components with hooks are the modern standard, lifecycle methods remain relevant because many enterprise-level applications still rely heavily on class-based components.
In this article, we will explore the three main phases of the React component lifecycle—mounting, updating, and unmounting—and the lifecycle methods associated with each phase. We will also provide detailed explanations, code examples, best practices, and real-world scenarios.
What Is a Component Lifecycle?
The component lifecycle refers to the series of events that happen from the time a component is created (mounted) until it is removed (unmounted) from the DOM.
Each React component goes through three major phases:
- Mounting – When the component is created and inserted into the DOM.
- Updating – When the component re-renders due to changes in props or state.
- Unmounting – When the component is removed from the DOM.
Lifecycle methods are special methods in class components that run automatically at each phase.
The Three Phases of Lifecycle
- Mounting Phase: Occurs when the component is first initialized and added to the DOM.
- Updating Phase: Occurs whenever props or state change and the component re-renders.
- Unmounting Phase: Occurs when the component is removed from the DOM.
Mounting Phase
The mounting phase is the first phase of the lifecycle. It happens when a component is being created and inserted into the DOM for the first time.
The lifecycle methods in the mounting phase are:
constructor()static getDerivedStateFromProps()render()componentDidMount()
1. constructor()
The constructor() method is the first method called when a component is created. It is used to:
- Initialize state
- Bind methods
- Set up initial values
Example
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.increment = this.increment.bind(this);
}
increment() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
2. static getDerivedStateFromProps()
This method is rarely used but is important. It runs before render() both on the initial mount and on updates. Its purpose is to synchronize state with props.
static getDerivedStateFromProps(props, state) {
if (props.value !== state.value) {
return { value: props.value };
}
return null;
}
3. render()
The render() method is required in every class component. It describes the UI that should be displayed. It must return JSX or null.
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
4. componentDidMount()
This method runs once after the component has been mounted into the DOM. It is often used for:
- Fetching data from APIs
- Adding event listeners
- Starting timers
class DataFetcher extends React.Component {
state = { data: [] };
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/posts")
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
return (
<ul>
{this.state.data.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
}
Updating Phase
The updating phase occurs whenever a component’s state or props change. This phase allows the component to re-render with updated data.
The lifecycle methods in the updating phase are:
static getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
1. shouldComponentUpdate()
This method determines whether a component should re-render or not. It returns a boolean value. By default, components re-render on every update, but you can override this for performance optimization.
shouldComponentUpdate(nextProps, nextState) {
return nextProps.value !== this.props.value;
}
2. render() (During Updates)
As in mounting, render() is called during updates to re-render the UI.
3. getSnapshotBeforeUpdate()
This method is called just before changes from the virtual DOM are applied to the real DOM. It allows capturing information, such as scroll position, before the DOM updates.
getSnapshotBeforeUpdate(prevProps, prevState) {
if (prevProps.list.length < this.props.list.length) {
return this.listRef.scrollHeight;
}
return null;
}
4. componentDidUpdate()
This method is invoked immediately after the component updates. It is commonly used for:
- Fetching data based on new props
- Performing side effects after updates
componentDidUpdate(prevProps, prevState) {
if (this.props.userId !== prevProps.userId) {
this.fetchData(this.props.userId);
}
}
Unmounting Phase
The unmounting phase happens when a component is removed from the DOM. There is only one lifecycle method in this phase:
componentWillUnmount()
This method is used for cleanup, such as:
- Removing event listeners
- Canceling API calls
- Clearing timers
class Timer extends React.Component {
componentDidMount() {
this.interval = setInterval(() => {
console.log("Tick");
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <h1>Timer Running...</h1>;
}
}
Full Lifecycle Flow
When a component is created:
constructor()getDerivedStateFromProps()render()componentDidMount()
When updated:
getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
When unmounted:
componentWillUnmount()
Example: Complete Lifecycle Demonstration
class LifecycleDemo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
console.log("Constructor");
}
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps");
return null;
}
componentDidMount() {
console.log("componentDidMount");
}
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate");
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate");
}
componentWillUnmount() {
console.log("componentWillUnmount");
}
render() {
console.log("Render");
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Increment
</button>
</div>
);
}
}
If you mount and interact with this component, you will see lifecycle methods logged in the console, showing when each one executes.
Best Practices for Lifecycle Methods
- Keep Logic Focused – Avoid putting too much logic inside lifecycle methods.
- Use componentDidMount for Side Effects – Fetch data, set up subscriptions here.
- Use componentWillUnmount for Cleanup – Always clear intervals or subscriptions.
- Avoid Deprecated Methods – Methods like
componentWillMountare deprecated. - Optimize Performance – Use
shouldComponentUpdatefor performance improvements.
Deprecated Lifecycle Methods
Some lifecycle methods are deprecated in newer versions of React (16.3+). They should not be used:
componentWillMount()componentWillReceiveProps()componentWillUpdate()
React recommends alternatives like getDerivedStateFromProps and componentDidUpdate.
Lifecycle Methods vs Hooks
In modern React, functional components with hooks (useEffect, useState) replace lifecycle methods. For example:
componentDidMount→useEffectwith empty dependency arraycomponentDidUpdate→useEffectwith dependenciescomponentWillUnmount→ Cleanup function inuseEffect
Real-World Use Cases
- Data Fetching – Fetch data when the component mounts.
- Event Listeners – Add in
componentDidMount, remove incomponentWillUnmount. - Performance Optimizations – Use
shouldComponentUpdate. - DOM Measurements – Use
getSnapshotBeforeUpdatefor scroll tracking. - Timers – Start in
componentDidMount, clear incomponentWillUnmount.
Common Mistakes
- Fetching data in
render()instead ofcomponentDidMount. - Forgetting to remove event listeners in
componentWillUnmount. - Updating state inside
componentDidUpdatewithout conditions, leading to infinite loops. - Overusing lifecycle methods for logic better suited in plain functions.
Leave a Reply