← All posts
ReactDebuggingJunior Dev

How to get unstuck in React (when Stack Overflow isn't enough)

The Mento Team·April 18, 2026·6 min read

It's 11pm. You've been staring at the same component for two hours. You've re-read the React docs three times. You've Googled every variation of your error message. You've copy-pasted four Stack Overflow answers, and your code is somehow worse now than when you started.

Every React developer — no matter how senior — has been in this exact spot. But junior devs hit a specific set of walls that trip up almost everyone at the same stage. The good news: once you understand whythese patterns bite you, they stop biting. Here's a practical guide to the three most common React traps, and how to actually get out of them.

The 3 React pitfalls that trap junior devs

After hundreds of pair-programming sessions with junior React developers, we see the same three problems come up again and again:

  1. Props drilling— passing data five levels deep through components that don't even need it
  2. Stale closures — when your event handlers and effects capture old state values and lie to you
  3. useEffect dependency arrays— the lint warnings you've been ignoring that are quietly causing bugs

Props drilling: when your component tree becomes a phone tree

You start with a simple prop. userId needs to get from your App down to a UserAvatar component. Fine. But a week later, UserAvatar is six components deep, and every component in between is threading userId as a prop even though it uses it for nothing. Your code reads like a broken game of telephone.

The fix isn't complicated: React's built-in Context API was built exactly for this. Wrap the relevant part of your tree in a Context Provider, and any component inside it can read the value directly — no drilling required.

But before you reach for Context, ask yourself: do you actually have a prop drilling problem, or a component composition problem? Often the real fix is to restructure your components so that the component that owns the data is closer to the component that needs it. Context adds indirection. Composition is usually cleaner.

A good rule of thumb: if a prop passes through more than two components that don't use it, it's time to either reach for Context or rethink your component boundaries.

Stale closures: when your code lies to you

This is the one that causes the most "but I just fixed that" debugging sessions. A stale closure happens when a function — inside a useEffect, an event handler, or a setTimeout — captures a value from state or props at the time it was created, and never sees the updated version.

Here's the classic trap:

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

  useEffect(() => {
    const interval = setInterval(() => {
      // BUG: count is always 0 here
      // The closure captured count = 0
      // and never saw updates
      console.log(count); // always 0
      setCount(count + 1); // always 0 + 1 = 1
    }, 1000);
    return () => clearInterval(interval);
  }, []); // empty deps = stale closure

  return <div>{count}</div>;
}

The counter will show 1 forever. The interval callback is frozen in time, holding a reference to count as it was when the effect first ran — which was 0.

The proper fix is to use the updater function form of setState — setCount(prev => prev + 1)— which doesn't rely on the closed-over value at all. For more complex cases with objects or multiple state values, a useRef can hold a mutable reference to the latest value that any closure can read without going stale.

Stale closures are why React Hooks have the lint rules they do. When ESLint tells you to add something to a dependency array and you suppress the warning instead — that's usually when the stale closure bug appears.

The useEffect dependency array: React's most misunderstood feature

Most junior devs learn one of two wrong mental models for useEffect: "it runs on mount" or "it runs every render." Neither is the right frame. The right frame is: useEffect synchronizes your component with something external, and the dependency array tells React when to re-synchronize.

The rule is simple but easy to violate: every value from your component that is used inside the effect must be in the dependency array. Props. State. Functions defined in the component body. All of it. If you leave something out, you get a stale closure (see above). If you add something that changes every render (like an object literal or inline function), you get an infinite loop.

The most common mistake: useEffect(() => { fetchData(userId) }, []) — the developer wants to fetch once on mount, but if userId changes, the effect never re-runs. The data goes stale. The fix: [userId] in the dependency array, and a proper cleanup or abort controller to handle race conditions.

If you find yourself fighting the dependency array, that's usually a signal that the effect itself is doing too much, or that your data fetching belongs in a library like React Query or SWR instead of raw useEffect. These tools exist because "fetch in useEffect" is genuinely one of React's harder patterns to get right.

When Stack Overflow just isn't enough

Here's the honest truth about Stack Overflow: it's great at answering genericquestions. "How does useEffect work?" — answered. "What is a stale closure?" — answered. But when you're actually stuck, the question isn't generic. It's specific: why is THIS code, in THIS project, with THESE constraints, doing THIS weird thing?

A Stack Overflow answer can't see your component tree. It can't ask you a follow-up question. It can't spot that your bug is actually three layers up from where you're looking. It can't watch you try the fix and immediately see what you're still misunderstanding.

A senior React developer can do all of that. In real time. Sharing your screen. The average Mento session unblocks developers in under 40 minutes — not because senior devs are magic, but because having another set of eyes on your actual code, with someone who can ask questions and spot patterns, is a fundamentally different kind of help.

Stop Googling. Start Shipping.

Get unstuck in 60 minutes — guaranteed

Book a live 1:1 session with a senior React developer. Share your screen, explain your problem, and leave with working code and a clear mental model. $45 for one hour.

Book your session now →

No subscription. Cancel anytime. 30-day money-back guarantee.

M
The Mento Team

Mento connects junior React developers with senior contractors for focused $45/hr pair-programming sessions. We've helped 200+ developers get unstuck, ship faster, and actually understand their code.