# I Finally Understood JavaScript Closures (And Why They Matter in React)

### The "Magic" Black Box

For the longest time, I treated certain parts of JavaScript as "magic." especially when I started learning the MERN stack.

I would write const \[count, setCount\] = useState(0) in React, and somehow, React would "remember" the value of count even after the component function finished running and re-rendered.

*How does it remember?* The function ran, finished, and closed. The variable should be gone, right?

The answer isn't magic. It's **Closures**. And honestly, it took me an embarrassing amount of time to actually "get" it.

### The "Backpack" Analogy

The textbook definition of a closure is: *"A combination of a function bundled together (enclosed) with references to its surrounding state."*

That makes my eyes glaze over.

Here is the mental model that finally clicked for me: **The Backpack.**

When a function is created in JavaScript, it doesn't just come with its code. It comes with a hidden "backpack." Inside that backpack, it packs up all the variables that existed in its parent scope at the time it was born.

Even if the parent function finishes executing and disappears, the child function carries that backpack wherever it goes.

### The Code Proof

Let’s look at vanilla JavaScript before we touch React.

```bash
function createCounter() {
  let count = 0; // This variable belongs to createCounter

  return function increment() {
    count++; // The inner function uses the outer variable
    console.log(count);
  };
}

const myCounter = createCounter(); 
// At this point, createCounter() has finished running. 
// Ideally, 'count' should be garbage collected and deleted.

myCounter(); // Output: 1
myCounter(); // Output: 2
myCounter(); // Output: 3
```

**Why this works:**  
When myCounter (the increment function) was returned, it didn't leave empty-handed. It grabbed count and put it in its closure (backpack). Every time we call myCounter, it reaches into that backpack to update the value.

### Why MERN Developers Should Care (React Hooks)

If you use React, you rely on closures every single day.

When you use useState, React is essentially doing what we did above: keeping state variables alive inside a closure that sits outside your component.

However, closures are also the source of the most frustrating bugs in React, specifically **Stale Closures**.

Have you ever used a useEffect and wondered why your state variable isn't updating inside it?

```bash
// The "Stale Closure" Trap
useEffect(() => {
  const timer = setInterval(() => {
    console.log(count); // ALWAYS prints 0, even if count increases!
  }, 1000);

  return () => clearInterval(timer);
}, []); // Empty dependency array
```

**The Explanation:**  
The function inside setInterval was created on the *first render*. It packed the value of count (which was 0) into its backpack.  
Even if count updates to 5, 10, or 100 elsewhere, that interval function is still holding onto the old backpack where count is 0.

To fix it, we have to force the function to pack a *new* backpack by adding \[count\] to the dependency array.

### Summary

Understanding closures shifted my mindset from "I hope this works" to "I know how this works."

It explains why:

1. Private variables exist in JavaScript patterns.
    
2. React Hooks maintain state.
    
3. Event listeners sometimes hold onto old data.
    

If you are struggling with a concept, don't just memorize the syntax. Try to visualize where the data lives. For me, visualizing the "Backpack" solved the puzzle.

> *This article is part of my "30 Days of Building" challenge. I'm documenting my journey building real-world projects and learning new tech.*
> 
> **Current Project:** Portfolio  
> **Portfolio:** [**https://uzairalam.me**](https://uzairalam.me)
> 
> ---
