The component lifecycle describes the different stages a React component goes through during its lifetime. A component is created, rendered, updated, and eventually removed from the screen.
Component lifecycle means the different stages a component experiences from the time it is created until it is removed from the user interface.
Common stages include:
Component
↓
Mount
↓
Update
↓
Unmount
React components generally go through three important stages:
These stages help developers understand when different operations occur.
Mounting happens when a component is created and inserted into the user interface for the first time.
For example:
function Welcome() {
return <h2>Welcome to React</h2>;
}
When Welcome is rendered for the first time, it is mounted.
During mounting, React renders the component and creates the required user interface.
function App() {
return (
<div>
<Welcome />
</div>
);
}
The Welcome component is rendered when the application displays it.
A component is updated when its state or props change.
For example:
const [count, setCount] = useState(0);
setCount(count + 1);
Changing the state can cause React to render the component again with the new value.
State is one of the most common reasons a component updates.
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
Every state update can cause React to render the component with updated data.
Props can also cause a component to update when a parent passes new values.
function Student({ name }) {
return <h3>Student: {name}</h3>;
}
If the parent changes the name prop, React can render the component
again with the new value.
A re-render means React runs the component function again to determine what the UI should look like with the current data.
function App() {
console.log("Rendering");
return <h1>Hello React</h1>;
}
A state or props change may cause this component to render again.
Unmounting happens when a component is removed from the user interface.
For example:
{show && <Message />}
When show becomes false, the Message
component is removed from the screen.
In modern React, the useEffect Hook is commonly used to perform
side effects and synchronize a component with external systems.
useEffect(() => {
console.log("Effect executed");
}, []);
The empty dependency array means the effect is set up after the component is initially mounted.
An effect with an empty dependency array is commonly used for work that should run after the initial render.
useEffect(() => {
console.log("Component mounted");
}, []);
This pattern is useful for tasks such as initial data loading.
An effect can depend on a value. When that dependency changes, React runs the effect again.
useEffect(() => {
console.log("Count changed");
}, [count]);
Here, the effect reacts to changes in count.
An effect can return a cleanup function. Cleanup is useful when an effect creates something that needs to be stopped or removed.
useEffect(() => {
const timer = setInterval(() => {
console.log("Running");
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
When a component using an effect is removed, React can run the effect's cleanup function.
useEffect(() => {
const timer = setInterval(() => {
console.log("Hello");
}, 1000);
return () => clearInterval(timer);
}, []);
This prevents the timer from continuing after the component is removed.
Event listeners created inside an effect should usually be removed during cleanup.
useEffect(() => {
function handleResize() {
console.log(window.innerWidth);
}
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
Fetching data is a common side effect in React applications. An effect can be used to start data loading when appropriate.
useEffect(() => {
fetch("/api/students")
.then(response => response.json())
.then(data => {
console.log(data);
});
}, []);
The empty dependency array is commonly used when the request should start after the initial render.
Timers are another example of an external operation that may need cleanup.
useEffect(() => {
const timer = setTimeout(() => {
console.log("Done");
}, 3000);
return () => {
clearTimeout(timer);
};
}, []);
Conditional rendering can determine whether a component is currently mounted.
function App() {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>
Toggle
</button>
{show && <Message />}
</div>
);
}
When show changes, the Message component may be
mounted or unmounted.
React applications usually contain a tree of components.
App
├── Header
├── Main
│ ├── StudentList
│ └── StudentCard
└── Footer
Each component can have its own rendering and lifecycle behavior.
A parent component can render a child component and pass data to it using props.
function App() {
return <Student name="Rahul" />;
}
function Student({ name }) {
return <h2>{name}</h2>;
}
Changes in the parent can result in the child receiving new props.
Modern functional React components do not use the old class lifecycle methods as their primary approach.
Instead, functional components use Hooks such as:
useStateuseEffectuseRefThese Hooks help manage state, effects, references, and other component logic.
Older React applications may contain class components with lifecycle methods. Some common methods include:
componentDidMount()componentDidUpdate()componentWillUnmount()These methods correspond to common mounting, updating, and unmounting tasks in class components.
In class components, componentDidMount() runs after the component
has been mounted.
class App extends React.Component {
componentDidMount() {
console.log("Mounted");
}
render() {
return <h1>Hello</h1>;
}
}
This method is mainly encountered when working with older class-based React code.
In class components, componentDidUpdate() runs after an update.
componentDidUpdate() {
console.log("Component updated");
}
It can be used to respond to changes after an update in class-based code.
In class components, componentWillUnmount() runs before a
component is removed from the screen.
componentWillUnmount() {
console.log("Component will be removed");
}
It is commonly associated with cleanup operations in older class components.
Modern React applications commonly use functional components and Hooks instead of class lifecycle methods.
function Profile() {
useEffect(() => {
console.log("Effect started");
return () => {
console.log("Cleanup");
};
}, []);
return <h2>Profile</h2>;
}
Not every calculation or state update requires an effect. If a value can be calculated directly during rendering, an effect may not be necessary.
const fullName = firstName + " " + lastName;
This is a normal calculation and does not need useEffect.
A simple lifecycle flow can be understood like this:
1. Component is created
↓
2. Component renders
↓
3. Component is displayed
↓
4. State/props change
↓
5. Component renders again
↓
6. Component is removed
↓
7. Cleanup runs when required
This model is useful for understanding React applications.
import { useEffect, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Effect started");
return () => {
console.log("Cleanup");
};
}, [count]);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
export default Counter;
When count changes, the component renders again and the effect
responds to the dependency change.
useEffect for appropriate side effects.Mount → Update → Unmount
useEffect is commonly used for side effects and synchronization.Question: What does the React component lifecycle describe?