React components have a lifecycle that allows you to control what happens at different stages of a component’s existence. Here’s a breakdown of the key lifecycle phases and methods:
1. Mounting Phase (Component Creation)
Class Components
constructor()– Initializes state and binds methodsstatic getDerivedStateFromProps()– Updates state based on props (rarely used)render()– Returns JSX to displaycomponentDidMount()– Runs after component is mounted to DOM (ideal for API calls, subscriptions)
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { data: null };
}
componentDidMount() {
fetchData().then(data => this.setState({ data }));
}
render() {
return <div>{this.state.data}</div>;
}
}
Functional Components Equivalent
function Example() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []); // Empty dependency array = runs once on mount
return <div>{data}</div>;
}
2. Updating Phase (Re-rendering)
Class Components
static getDerivedStateFromProps()– Sync state to propsshouldComponentUpdate()– Optimize by preventing unnecessary rendersrender()– Re-renders JSXgetSnapshotBeforeUpdate()– Capture DOM info before updatecomponentDidUpdate()– Runs after update completes
class Example extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.id !== this.props.id; // Only update if id changes
}
componentDidUpdate(prevProps) {
if (this.props.id !== prevProps.id) {
this.fetchData(this.props.id);
}
}
}
Functional Components Equivalent
function Example({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
fetchData(id).then(setData);
}, [id]); // Re-runs only when id changes
return <div>{data}</div>;
}
3. Unmounting Phase (Component Removal)
Class Components
componentWillUnmount()– Cleanup before removal (cancel timers, subscriptions)
class Example extends React.Component {
componentDidMount() {
this.timer = setInterval(() => {}, 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
}
Functional Components Equivalent
function Example() {
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer); // Cleanup function
}, []);
}
4. Error Handling
Class Components
static getDerivedStateFromError()– Render fallback UI after errorcomponentDidCatch()– Log error information
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logErrorToService(error, info);
}
}
Functional Components Equivalent
(Requires class component for error boundaries – no hook equivalent yet)
Lifecycle Cheat Sheet
| Phase | Class Method | Hook Equivalent |
|---|---|---|
| Mounting | componentDidMount() | useEffect(() => {}, []) |
| Updating | componentDidUpdate() | useEffect(() => {}, [deps]) |
| Unmounting | componentWillUnmount() | useEffect(() => { return cleanup }, []) |
| State from Props | getDerivedStateFromProps() | useMemo, useState with props |
| Performance Opt | shouldComponentUpdate() | React.memo, useMemo, useCallback |
Key Takeaways
- Class components use explicit lifecycle methods
- Functional components use
useEffectto handle most lifecycle needs useEffectcombinescomponentDidMount,componentDidUpdate, andcomponentWillUnmount- Error boundaries still require class components
- Modern React favors functional components with hooks
