Skip to content

React Hooks: Mastering useEffect (Casual Guide)

Posted on:January 7, 2026 at 10:00 AM

Hey there, Fellow Coder! 👋

Remember how we talked about State being the component’s memory? Well, today we’re going to talk about its “senses” or “reactions”.

We’re diving into useEffect.

A lot of people find this hook confusing. “When does it run?”, “Why is it looping infinitely?!”, “What is this dependency array thing?“.

Relax. Grab your coffee. We’re going to make this crystal clear. ☕

What is a “Side Effect”?

Before we touch the code, let’s talk concept. In React, a component’s main job is to render UI (show HTML).

But sometimes, your component needs to do things outside of just showing UI. things like:

These are called Side Effects. They are “side missions” that run alongside the main mission of rendering.

useEffect is the tool React gives us to handle these side missions.


1. The Basics: How to Use It

To use it, you import it just like useState.

import { useEffect, useState } from "react";

const Timer = () => {
  const [count, setCount] = useState(0);

  // This is the Effect
  useEffect(() => {
    console.log("Effect ran!");
    document.title = `Count: ${count}`;
  });

  return <button onClick={() => setCount(count + 1)}>Click me: {count}</button>;
};

Wait, when does it run? By default (like the code above), useEffect runs after every single render.

  1. Component appears (mount) -> Effect runs.
  2. You click button -> State changes -> Re-render -> Effect runs again.

This is often
 too much. We usually don’t want to fetch data every time a user clicks a button.


2. The Dependency Array []: controlling the Chaos

This is where the magic happens. The second argument of useEffect is an array []. This tells React: “Hey, only run this effect if THESE specific things change.”

Scenario A: The Empty Array []

useEffect(() => {
  console.log("I only run ONCE when the component mounts.");
}, []); // <--- Empty array

This is perfect for things you only want to do once, like fetching data when the page loads. It’s the modern replacement for componentDidMount.

Scenario B: Watching Specific Variables

useEffect(() => {
  console.log("I run when 'count' changes!");
}, [count]); // <--- Watch 'count'

Now, the effect runs on mount, AND whenever count changes. If count stays the same, React skips the effect. Efficient! ⚡


3. The Cleanup Function: Don’t Leave a Mess

Imagine you set up a party (an effect). When the party is over (component unmounts), you need to clean up the trash.

In code, this happens with things like Timers or Event Listeners. If you don’t clean them up, they keep running in the background and eat up memory (memory leaks).

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

  // This is the cleanup function
  return () => {
    clearInterval(timer); // Stop the timer!
    console.log("Cleanup done!");
  };
}, []);

React calls this cleanup function when:

  1. The component is removed from the screen (unmount).
  2. Before re-running the effect (if dependencies change).

Simple Analogy 🧠

Think of useEffect like a Smart Sprinkler System for your garden (component).

Closing

That’s it! useEffect is just a way to synchronize your component with the outside world.

  1. Default: Runs every render.
  2. []: Runs once on mount.
  3. [data]: Runs when data changes.
  4. Return function: Cleans up the mess.

Master this, and you’ve mastered 80% of modern React challenges. Next time, we might build something real with this.

Happy Coding! 🚀