componentDidMount fires exactly once per component instance, right after that component's first render has been committed to the real DOM — this makes it the traditional class-component place to perform initial side effects like fetching data, setting up a subscription, or reading a DOM node's measurements, since the actual DOM elements are guaranteed to exist by this point, unlike during render() itself. In functional components, the equivalent behavior is achieved with useEffect(() => { ... }, []), an effect with an empty dependency array, which likewise runs exactly once after the initial mount.
1Understanding ComponentDidMount
componentDidMount fires exactly once per component instance, right after that component's first render has been committed to the real DOM — this makes it the traditional class-component place to perform initial side effects like fetching data, setting up a subscription, or reading a DOM node's measurements, since the actual DOM elements are guaranteed to exist by this point, unlike during render() itself. In functional components, the equivalent behavior is achieved with useEffect(() => { ... }, []), an effect with an empty dependency array, which likewise runs exactly once after the initial mount.
componentDidMount's functional-component equivalent is useEffect(() => { ... }, []) — an empty dependency array specifically means the effect runs once, matching componentDidMount's once-per-mount behavior.
class UserProfile extends React.Component {
state = { name: null };
componentDidMount() {
console.log('Component mounted, fetching data...');
fetchUser(this.props.userId).then(user => this.setState({ name: user.name }));
}
render() {
return <p>{this.state.name ?? 'Loading...'}</p>;
}
}2Practical Example
Here is a real-world application of ComponentDidMount showing how it is used in production React code.
class ClickTracker extends React.Component {
componentDidMount() {
document.addEventListener('click', this.logClick);
}
componentWillUnmount() {
document.removeEventListener('click', this.logClick);
}
logClick = () => console.log('Document clicked');
render() {
return <p>Tracking clicks...</p>;
}
}3Best Practices
Follow these guidelines when working with ComponentDidMount:
1. Perform initial data fetching, subscriptions, or DOM measurements in componentDidMount, since the component's actual DOM nodes are guaranteed to exist by that point
2. Avoid calling this.setState() synchronously and unconditionally inside componentDidMount without a real reason, since it triggers an extra, avoidable re-render right after the initial one
3. Recognize componentDidMount only appears in class components — write the equivalent useEffect(fn, []) when working in functional components instead
Tip: componentDidMount's functional-component equivalent is useEffect(() => { ... }, []) — an empty dependency array specifically means the effect runs once, matching componentDidMount's once-per-mount behavior.
class UserProfile extends React.Component {
state = { name: null };
componentDidMount() {
console.log('Component mounted, fetching data...');
fetchUser(this.props.userId).then(user => this.setState({ name: user.name }));
}
render() {
return <p>{this.state.name ?? 'Loading...'}</p>;
}
}