Skip to content

Component Lifecycle

Every React component goes through a lifecycle: it appears on the screen (mounting), updates when state or props change (updating), and is removed from the screen (unmounting). Understanding this lifecycle helps you manage side effects, avoid memory leaks, and write predictable components.


The component is created, rendered for the first time, and inserted into the DOM.

The component re-renders because its state changed, props changed, or a parent re-rendered.

The component is removed from the DOM. Cleanup happens here (intervals, subscriptions, event listeners).


flowchart LR
Mount["🟢 Mount<br/>Component appears"] --> Update["🔵 Update<br/>State/props change"]
Update --> Update
Update --> Unmount["🔴 Unmount<br/>Component removed"]

In class components, lifecycle methods let you hook into each phase:

PhaseMethodPurpose
Mountconstructor()Initialize state, bind handlers
Mountrender()Return JSX
MountcomponentDidMount()Fetch data, set up subscriptions
Updaterender()Re-render with new state/props
UpdatecomponentDidUpdate(prevProps)React to prop/state changes
UnmountcomponentWillUnmount()Clean up intervals, subscriptions
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState(s => ({ seconds: s.seconds + 1 }));
}, 1000);
}
componentDidUpdate(prevProps) {
if (prevProps.timerId !== this.props.timerId) {
console.log('Timer ID changed, resetting...');
this.setState({ seconds: 0 });
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <p>Elapsed: {this.state.seconds}s</p>;
}
}

Explanation: The timer starts when mounted (componentDidMount), tracks the timer ID for potential resets (componentDidUpdate), and stops when unmounted (componentWillUnmount). The lifecycle methods are split across the class.


Functional components use useEffect to handle lifecycle behaviors. A single useEffect can combine mount, update, and unmount logic.

import { useState, useEffect } from 'react';
export default function Timer({ timerId }) {
const [seconds, setSeconds] = useState(0);
// Equivalent to componentDidMount + componentWillUnmount
useEffect(() => {
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
// Cleanup: equivalent to componentWillUnmount
return () => clearInterval(interval);
}, []); // Empty deps = run once on mount
// Equivalent to componentDidUpdate
useEffect(() => {
setSeconds(0);
}, [timerId]); // Runs when timerId changes
return <p>Elapsed: {seconds}s</p>;
}

Class MethodFunctional Equivalent
constructoruseState initializer / lazy init
componentDidMountuseEffect(() => {}, [])
componentDidUpdateuseEffect(() => {}, [deps])
componentWillUnmountCleanup function in useEffect return
shouldComponentUpdateReact.memo
getDerivedStateFromPropsDerive state during render

sequenceDiagram
participant Component
participant React
participant Effect
Component->>React: Render JSX
React->>React: Commit to DOM
React->>Effect: Run effect callback
Effect->>Effect: Store cleanup function
Note over Component: State/props change
Component->>React: Re-render
React->>Effect: Run previous cleanup
React->>Effect: Run new effect
Note over Component: Unmount
React->>Effect: Run final cleanup

⚠ Missing Cleanup

Starting an interval or subscription without cleanup causes memory leaks. The interval continues running even after the component unmounts.

// ❌ BAD — interval leaks on unmount
useEffect(() => {
setInterval(() => console.log('tick'), 1000);
}, []);
// ✅ GOOD — cleanup clears the interval
useEffect(() => {
const id = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(id);
}, []);

⚠ Unnecessary Dependencies

Including an inline function or object in the dependency array without memoization causes infinite re-renders. Always use useCallback for stable callbacks.


  • Mount: Component appears. Set up subscriptions, fetch data.
  • Update: Component re-renders. Respond to prop/state changes.
  • Unmount: Component removed. Clean up subscriptions, intervals.
  • In functional components, useEffect with [] = mount/unmount. useEffect with [deps] = didUpdate.
  • Always clean up to prevent memory leaks.