Class vs function component lifecycle
The main difference
| Class components | Function components |
|---|---|
Use lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount, and others) | Use hooks (useEffect, useLayoutEffect, useMemo, and so on) |
| React calls the methods itself at the right moment | Hooks give you a more flexible and more universal way to control these moments |
| Logic is "scattered" across different methods | Logic is "gathered" in one place and can be extracted into custom hooks |
Lifecycle of a class component
Main stages and methods:
| Stage | Method | When it fires | Hook equivalent |
|---|---|---|---|
| Mounting | constructor() | When the class instance is created | - |
componentDidMount() | After the first render and insertion into the DOM | useEffect(() => {...}, []) | |
| Updating | componentDidUpdate(prevProps, prevState) | After state or props update | useEffect(() => {...}, [deps]) |
| Unmounting | componentWillUnmount() | Before removal from the DOM | useEffect(() => { return () => {...} }, []) |
Example (classic)
javascript
class Timer extends React.Component {
state = { seconds: 0 };
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <p>Seconds elapsed: {this.state.seconds}</p>;
}
}Lifecycle of a function component
In the "function world" there are no separate methods - everything is handled with hooks.
The main tool is useEffect.
Stage equivalents:
| Stage | How it is implemented |
|---|---|
| Mounting | useEffect(() => {...}, []) |
| Updating | useEffect(() => {...}, [deps]) |
| Unmounting | useEffect(() => { return () => {...} }, []) |
Example (the hooks equivalent)
javascript
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const id = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(id); // cleanup - the componentWillUnmount equivalent
}, []);
return <p>Seconds elapsed: {seconds}</p>;
}Key differences in approach
| # | Class component | Function component |
|---|---|---|
| 1 | Split across methods (componentDidMount, componentDidUpdate, …) | Everything happens inside useEffect with dependencies |
| 2 | Logic is "smeared" across different places | Logic is grouped by meaning (hooks can be extracted into custom ones) |
| 3 | Has this and state via this.state / this.setState | Uses useState / useReducer, no this |
| 4 | setState is always asynchronous and merges objects | useState works with any type of data, including objects and functions |
| 5 | A single class instance lives the whole time | The function is called again on every render |
| 6 | Hard to reuse logic (only HOC or render props) | Easy to split and reuse via custom hooks |
| 7 | A more "imperative" style | A more "declarative" and functional style |
Illustration
The class approach:
javascript
constructor()
↓
render()
↓
componentDidMount()
↓
componentDidUpdate()
↓
componentWillUnmount()The function approach:
javascript
Render → useEffect(() => {...}, [])
Render → useEffect(() => {...}, [deps])
Unmount → cleanup()Why React moved to hooks
- Hooks simplify the code: less boilerplate (
this, bind, constructor). - They let you split logic by meaning, not by stage.
- They make logic reuse easier (via custom hooks).
- They work better with TypeScript and a functional style.
- They support Concurrent Rendering (React 18+).
Summary
| Aspect | Class component | Function component |
|---|---|---|
| Lifecycle API | Methods (componentDidMount, componentDidUpdate, componentWillUnmount) | Hooks (useEffect, useLayoutEffect, cleanup functions) |
| State | this.state + this.setState() | useState, useReducer |
| Context | contextType | useContext() |
| Complexity of logic | Scattered across methods | Focused in hooks |
| Reuse | Via HOC/render props | Via custom hooks |
| "this" | Present | Absent |
| Performance / convenience | More cumbersome | More declarative and flexible |
The main idea:
Class components manage the lifecycle through separate methods, while function components do it through hooks (
useEffect), which combine all the lifecycle logic in one place and make it easy to reuse.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.