# Mastering useEffect in React: A Fun Guide with Counter, Data, and Timer Examples

If you’re learning React, chances are you’ve heard about `useEffect` and wondered:

> "Why does this hook exist? Why not just write everything in functions?"

Well, let’s break it down with an **easy and fun example**. We’ll build a little app that:

* Keeps track of a **count**
    
* Keeps track of some **data**
    
* Runs a **timer** that can start and stop
    

And along the way, we’ll see how `useEffect` works in 3 different modes.

```javascript
import React, { useEffect, useState } from "react";

const App = () => {
  // React states to hold different values
  const [count, setCount] = useState(0); // keeps track of count
  const [data, setData] = useState(10); // keeps track of data
  const [start, setStart] = useState(false); // flag to check if timer started or stopped
  const [seconds, setSeconds] = useState(0); // timer counter

  // A simple function that logs a message
  const getExecuted = () => {
    console.log("hi i will get executed always");
  };

  // Function to increase count
  const Increment = () => {
    setCount((prev) => prev + 1);
  };

  // Function to update data
  const updateData = () => {
    setData((prev) => prev + 10);
  };

  // useEffect without dependency array → runs EVERY time component re-renders
  useEffect(() => {
    getExecuted();
  }); // run on every render

  // useEffect with empty array → runs ONLY once when component mounts
  useEffect(() => {
    console.log("hi i will get executed once");
  }, []); // run only once

  // useEffect with [data] dependency → runs when 'data' value changes
  useEffect(() => {
    console.log("hi i am will get executed when data will change", data);
  }, [data]); // runs whenever data updates

  // Timer logic
  useEffect(() => {
    let interval;
    if (start) {
      console.log("Timer started");
      interval = setInterval(() => {
        // increment seconds every 1 second
        setSeconds((prev) => prev + 1);
      }, 1000);
    } else {
      console.log("Timer stopped");
    }

    // cleanup function → clears the timer when component unmounts or 'start' changes
    return () => {
      if (interval) clearInterval(interval);
      console.log("Timer cleaned up");
    };
  }, [start]); // runs whenever start (true/false) changes

  return (
    <div>
      <h1>Count: {count}</h1>
      <h2>Data: {data}</h2>
      {/* Buttons to update count and data */}
      <button onClick={Increment}>Increment Count</button>
      <button onClick={updateData}>Update Data</button>

      {/* Timer Display */}
      <h2>Timer: {seconds} sec</h2>

      {/* Timer controls */}
      <button onClick={() => setStart(true)}>▶ Start</button>
      <button onClick={() => setStart(false)}>⏹ Stop</button>
    </div>
  );
};

export default App;
```

### ⚙️ The Code

(You saw the full code above 👆. Don’t worry, we’ll explain it step by step.)

### 1\. 📊 States: Our App’s Memory

### » We use `useState` to keep track of different things:

```javascript
const [count, setCount] = useState(0);
const [data, setData] = useState(10);
const [start, setStart] = useState(false);
const [seconds, setSeconds] = useState(0);
```

» Think of states like **notebooks** in which React writes stuff down.

* `count` is like the number of cookies eaten.
    
* `data` is some random number we increase by 10.
    
* `start` is a switch for the timer (on/off).
    
* `seconds` is literally the timer counting.
    

### 2\. 🔁 `useEffect` #1 – Runs on Every Render

```javascript
useEffect(() => {
  getExecuted();
}); 
```

This guy runs **every single time the component re-renders**.  
Imagine someone shouting "I’m alive!" every time your app blinks. That’s this effect.

### 3\. 🎉 `useEffect` #2 – Runs Only Once

```javascript
useEffect(() => {
  console.log("hi i am will get executed when data will change", data);
}, [data]);
```

This one is smarter — it runs only when `data` changes.  
So if you eat 10 more cookies 🍪, React says: "Oh! Data changed, let me run this again.

### 5\. ⏱ Timer with Cleanup

The most exciting part — a **timer**:

```javascript
useEffect(() => {
  let interval;
  if (start) {
    console.log("Timer started");
    interval = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);
  } else {
    console.log("Timer stopped");
  }

  return () => {
    if (interval) clearInterval(interval);
    console.log("Timer cleaned up");
  };
}, [start]);
```

* When you hit ▶ **Start**, it begins counting seconds.
    
* When you hit ⏹ **Stop**, the timer halts.
    
* The **cleanup function** makes sure we don’t create a new timer on top of an old one (otherwise, chaos: multiple timers racing 🏎️).
    

### 🎯 Final Thoughts

This little app is like a **playground for learning** `useEffect`. You saw:

1. How it runs on **every render**
    
2. How it runs **only once**
    
3. How it runs **only when a dependency changes**
    
4. How to use it with **timers and cleanup**
    

So the next time someone asks:  
👉 “When should I use `useEffect`?”

You can say:

* When you want something to happen **every time** → no dependencies
    
* When you want something to happen **only once** → empty array `[]`
    
* When you want something to happen **when X changes** → `[X]`
    

Now it’s your turn 🎮:  
👉 Try adding a **Reset Timer** button. Or maybe a **Pause/Resume** button. Once you do that, you’ll be officially leveling up in React! .

💡 If you enjoyed this post, share it with your developer friends or drop a comment with what you want me to explain next. And don’t forget to bookmark this page for quick React refreshers.
