In React.js, state and lifecycle methods are fundamental concepts that allow you to create dynamic and interactive applications. Understanding how state works and how to manage component lifecycle events is crucial for building efficient and responsive user interfaces. In this chapter, we will explore state and lifecycle methods in detail, starting from the basics and gradually moving towards more advanced topics.
State is a built-in object in React components that holds data that can change over time. Unlike props, which are read-only and passed from parent to child components, state is managed within the component itself and can be modified through setState or the useState hook.
In class components, state is initialized in the constructor and updated using the setState method.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
Count: {this.state.count}
);
}
}
export default Counter;
Counter is a class component.this.state is initialized in the constructor with count set to 0.increment method updates the state using this.setState.render method displays the current count and a button to increment it.
Count: 0
In functional components, state is managed using the useState hook.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
Count: {count}
);
}
export default Counter;
Counter is a functional component.useState hook initializes count to 0 and provides a function setCount to update it.
Count: 0
Lifecycle methods are special methods in class components that are called at different stages of a component’s life. These methods allow you to run code at specific points in a component’s lifecycle.

Mounting is the phase when a component is being created and inserted into the DOM.
constructor(): Called before the component is mounted. Used for initializing state and binding event handlers.static getDerivedStateFromProps(): Called before rendering when new props or state are being received. Used to update the state in response to props changes.render(): Required method that returns the React elements.componentDidMount(): Called after the component is mounted. Ideal for making API calls and other side effects.
class LifecycleDemo extends React.Component {
constructor(props) {
super(props);
this.state = { data: null };
}
componentDidMount() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
if (this.state.data === null) {
return Loading...;
}
return Data: {this.state.data};
}
}
export default LifecycleDemo;
componentDidMount makes an API call after the component is mounted and updates the state with the fetched data.
Loading...
Data: [fetched data]
Updating is the phase when a component is being re-rendered as a result of changes to props or state.
static getDerivedStateFromProps(): Called before rendering when new props or state are being received.shouldComponentUpdate(): Called before rendering. Used to let React know if a component’s output is not affected by the current change in state or props.render(): Re-renders the component.getSnapshotBeforeUpdate(): Called right before the most recently rendered output is committed to the DOM. Used to capture some information from the DOM before it changes.componentDidUpdate(): Called after the component is updated. Used for performing operations after the DOM has been updated.
class UpdatingDemo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
shouldComponentUpdate(nextProps, nextState) {
return nextState.count % 2 === 0; // Re-render only if count is even
}
componentDidUpdate(prevProps, prevState) {
console.log(`Updated from ${prevState.count} to ${this.state.count}`);
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
Count: {this.state.count}
);
}
}
export default UpdatingDemo;
shouldComponentUpdate checks if the count is even before deciding to re-render.componentDidUpdate logs the previous and current count after the component updates.
Count: 0
Unmounting is the phase when a component is being removed from the DOM.
componentWillUnmount(): Called right before the component is unmounted and destroyed. Used for cleanup operations like clearing timers and canceling network requests.
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return Seconds: {this.state.seconds};
}
}
export default Timer;
componentWillUnmount clears the interval when the component is unmounted to prevent memory leaks.
Seconds: 0
Seconds: 1
Seconds: 2
React Hooks provide a way to use state and other React features in functional components, including lifecycle methods through hooks like useEffect.
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds => seconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return Seconds: {seconds};
}
export default Timer;
useEffect runs the provided effect after the component mounts.useEffect clears the interval when the component unmounts.For complex state logic, useReducer can be more appropriate than useState.
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
Count: {state.count}
);
}
export default Counter;
useReducer takes a reducer function and an initial state, returning the current state and a dispatch function.
Count: 0
Understanding state and lifecycle methods is crucial for building dynamic and interactive applications with React. Class components provide a clear structure for managing state and lifecycle events, while functional components with hooks offer a more modern and concise way to achieve the same goals. By mastering these concepts, you can create robust, efficient, and maintainable React applications.Happy coding !❤️
