Understanding React Component Lifecycle with Hooks

Last updated 2 months, 2 weeks ago | 105 views 75     5

Tags:- React

Introduction: Why the React Lifecycle (with Hooks) Matters

Every React component goes through a lifecycle—from mounting to updating and finally unmounting. In class-based components, we used lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.

But with the rise of functional components and React Hooks, we can now manage the entire lifecycle using Hooks like useEffect and useLayoutEffect.

Understanding how to control the lifecycle with hooks is essential for:

  • Fetching data

  • Setting up subscriptions or timers

  • Cleaning up on unmount

  • Optimizing rendering behavior

Let’s break it all down with examples you can actually use in production.


Component Lifecycle Stages (Class vs Functional)

Lifecycle in Class Components

Stage Class Method Description
Mounting componentDidMount After component is added to the DOM
Updating componentDidUpdate On state/props change
Unmounting componentWillUnmount Before component is removed

Lifecycle in Functional Components (with Hooks)

Stage Hook Used Equivalent to
Mounting useEffect(() => {}, []) componentDidMount
Updating useEffect(() => {}, [deps]) componentDidUpdate
Unmounting return () => {} inside useEffect componentWillUnmount

Managing Lifecycle with useEffect

✅ 1. useEffect on Mount (componentDidMount)

import React, { useEffect } from 'react';

function HelloComponent() {
  useEffect(() => {
    console.log('Component mounted!'); // Called once
  }, []);

  return <h1>Hello World</h1>;
}

Passing an empty dependency array [] makes it run once on mount.


✅ 2. useEffect on Update (componentDidUpdate)

useEffect(() => {
  console.log('Count changed:', count);
}, [count]); // Runs whenever `count` changes

You can track specific variables by including them in the dependencies array.


✅ 3. Cleanup on Unmount (componentWillUnmount)

useEffect(() => {
  const timer = setInterval(() => console.log('Tick'), 1000);

  return () => {
    clearInterval(timer); // Cleanup
    console.log('Component unmounted');
  };
}, []);

The cleanup function runs when the component is removed or before next effect run.


useLayoutEffect vs useEffect

Feature useEffect useLayoutEffect
Timing Runs after DOM painting Runs before DOM painting
Use case Data fetching, subscriptions DOM measurements, layout adjustments
Performance Non-blocking Blocking

Example:

useLayoutEffect(() => {
  // Runs before the browser paints
}, []);

⚠️ Use useLayoutEffect only when necessary to avoid layout thrashing.


useEffect Lifecycle Simulation Summary

Lifecycle Stage Hook Usage
On Mount useEffect(() => {}, [])
On Update useEffect(() => {}, [dependencies])
On Unmount useEffect(() => { return () => {} }, [])

✅ Full Functional Example: Counter with Mount/Update/Unmount Logs

import React, { useEffect, useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  // On Mount
  useEffect(() => {
    console.log('Component Mounted');
    return () => {
      console.log('Component Unmounted');
    };
  }, []);

  // On Update
  useEffect(() => {
    if (count > 0) {
      console.log('Count Updated:', count);
    }
  }, [count]);

  return (
    <div>
      <h2>Counter: {count}</h2>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;

Try this: Open your browser console to see logs as the component mounts, updates, and unmounts.


Tips & Common Pitfalls

✅ Best Practices

  • Use useEffect(() => {}, []) for fetching data on mount.

  • Clean up inside the useEffect return function (e.g., event listeners, timers).

  • Avoid unnecessary re-renders by limiting dependencies in the effect array.

  • Use custom hooks for reusable lifecycle logic.

❌ Common Pitfalls

Mistake Problem Fix
Omitting dependencies in useEffect Stale data or bugs Add all dependencies explicitly
Using useEffect for layout calc Flickering UI Use useLayoutEffect instead
Forgetting cleanup on unmount Memory leaks or duplicate listeners Always return cleanup in useEffect

Quick Comparison: Class vs Hook Lifecycle

Behavior Class Component Hook Equivalent
On mount componentDidMount() useEffect(() => {}, [])
On update componentDidUpdate() useEffect(() => {}, [value])
On unmount componentWillUnmount() return () => {} inside useEffect

Conclusion: Hooks Make Lifecycle Easier and Cleaner

With React Hooks, managing the component lifecycle is simpler, more readable, and more powerful than ever before. Whether you're fetching data, setting up a subscription, or cleaning up resources, useEffect and useLayoutEffect give you full control without class-based boilerplate.

Key Takeaways:

  • Replace class lifecycle methods with useEffect.

  • Always clean up side effects.

  • Choose useLayoutEffect only when DOM layout matters.

  • Break complex logic into custom hooks for reuse and clarity.