JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeQuestionsreact
PrevNext

Learn the concept

Hooks

react
mid
lifecycle

How do React component lifecycle methods map to hooks in functional components?

lifecycle
hooks
useEffect
class-components
migration
Quick Answer

useEffect with an empty dependency array replaces componentDidMount, useEffect with dependencies replaces componentDidUpdate, and the useEffect cleanup function replaces componentWillUnmount. However, hooks represent a different mental model focused on synchronizing with external systems rather than responding to lifecycle events.

Detailed Explanation

Class component lifecycle methods and hooks solve the same problems but with fundamentally different mental models. Class lifecycles are organized around when things happen (mount, update, unmount), while hooks are organized around what you're synchronizing with (data, subscriptions, DOM).

Lifecycle-to-Hook Mapping

| Class Lifecycle | Hook Equivalent | |----------------|----------------| | constructor | useState initial value or useRef | | componentDidMount | useEffect(fn, []) | | componentDidUpdate | useEffect(fn, [deps]) | | componentWillUnmount | useEffect cleanup function | | shouldComponentUpdate | React.memo or useMemo | | getDerivedStateFromProps | Compute during render (no hook needed) | | getSnapshotBeforeUpdate | No direct hook equivalent | | componentDidCatch | No hook equivalent (use class Error Boundaries) |

componentDidMount → useEffect(fn, [])

JSX
// Class
componentDidMount() {
  fetchData();
  document.title = 'Loaded';
}
 
// Hook — empty dependency array = run once after first render
useEffect(() => {
  fetchData();
  document.title = 'Loaded';
}, []);

componentDidUpdate → useEffect(fn, [deps])

JSX
// Class
componentDidUpdate(prevProps) {
  if (prevProps.userId !== this.props.userId) {
    fetchUser(this.props.userId);
  }
}
 
// Hook — runs when userId changes
useEffect(() => {
  fetchUser(userId);
}, [userId]);

The hook version is simpler: you declare what you depend on, and React handles when to re-run.

componentWillUnmount → cleanup function

JSX
// Class
componentWillUnmount() {
  socket.disconnect();
  clearInterval(this.timerId);
}
 
// Hook — return a cleanup function from useEffect
useEffect(() => {
  const timerId = setInterval(tick, 1000);
  socket.connect();
 
  return () => {
    clearInterval(timerId);
    socket.disconnect();
  };
}, []);

The cleanup function also runs before the effect re-runs (on dependency changes), not just on unmount. This prevents stale subscriptions.

The Mental Model Shift

The key insight is that hooks don't map 1:1 to lifecycle methods. A single useEffect can combine mount + update + unmount logic for one concern, while class components scatter related logic across multiple lifecycle methods:

JSX
// Class — related logic split across 3 methods
componentDidMount() { subscribe(this.props.id); }
componentDidUpdate(prev) {
  if (prev.id !== this.props.id) {
    unsubscribe(prev.id);
    subscribe(this.props.id);
  }
}
componentWillUnmount() { unsubscribe(this.props.id); }
 
// Hook — all related logic in one place
useEffect(() => {
  subscribe(id);
  return () => unsubscribe(id);
}, [id]); // Handles mount, update, AND unmount

No Hook Equivalents

  • getSnapshotBeforeUpdate — Captures DOM state before an update (e.g., scroll position). No hook equivalent; use useRef + useLayoutEffect as a workaround.
  • componentDidCatch / Error Boundaries — Must use class components. There is no useErrorBoundary hook in React (though libraries like react-error-boundary provide one).

Code Examples

Complete Lifecycle-to-Hooks MigrationJSX
// CLASS COMPONENT
class UserProfile extends React.Component {
  state = { user: null, loading: true };

  componentDidMount() {
    this.fetchUser();
    document.title = 'Profile';
  }

  componentDidUpdate(prevProps) {
    if (prevProps.userId !== this.props.userId) {
      this.fetchUser();
    }
  }

  componentWillUnmount() {
    document.title = 'App'; // Reset title
  }

  async fetchUser() {
    this.setState({ loading: true });
    const res = await fetch(`/api/users/${this.props.userId}`);
    const user = await res.json();
    this.setState({ user, loading: false });
  }

  render() {
    if (this.state.loading) return <p>Loading...</p>;
    return <h1>{this.state.user.name}</h1>;
  }
}

// FUNCTIONAL COMPONENT WITH HOOKS
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;

    async function fetchUser() {
      setLoading(true);
      const res = await fetch(`/api/users/${userId}`);
      const data = await res.json();
      if (!cancelled) {
        setUser(data);
        setLoading(false);
      }
    }

    fetchUser();
    return () => { cancelled = true; }; // Cleanup: prevent stale updates
  }, [userId]); // Re-runs when userId changes

  useEffect(() => {
    document.title = 'Profile';
    return () => { document.title = 'App'; }; // Cleanup on unmount
  }, []);

  if (loading) return <p>Loading...</p>;
  return <h1>{user.name}</h1>;
}

Real-World Applications

Use Cases

Legacy Code Migration

Migrating class components to functional components in existing codebases requires understanding the lifecycle-to-hooks mapping to preserve behavior.

Side Effect Management

Understanding the hooks mental model helps organize effects by concern (data fetching, subscriptions, DOM manipulation) rather than by timing (mount, update, unmount).

Mini Projects

Class-to-Hooks Converter

intermediate

Take a class component with multiple lifecycle methods and refactor it to use hooks. Compare the before/after code and verify identical behavior.

Industry Examples

Meta

Facebook's codebase migrated thousands of class components to hooks, finding that hooks reduced related code fragmentation and made components easier to test and reuse.

Resources

React Docs - Synchronizing with Effects

docs

React Docs - You Might Not Need an Effect

docs

Related Questions

Explain the useState and useEffect hooks and their common patterns.

mid
hooks

What are custom hooks and how do you create them?

mid
hooks
Previous
What are React Fragments and when should you use them?
Next
When should you use Context API vs Redux for state management?
PrevNext