Hey React devs! If you’ve ever looked back at your own code and thought, “Wait, why did I do it like that?”—you’re not alone. Over-engineering and anti-patterns sneak up on all of us, whether building your first app or wrangling a giant codebase.
Today, let’s explore mistakes nearly every React developer makes (yes, including me), and how you can sidestep them for faster, cleaner projects.
Why Do Anti-Patterns Happen (and Why Care)?
React gives us loads of freedom, but that leaves room for confusion and blunders. Anti-patterns are habits or shortcuts that feel like a good idea but end up causing bugs, slow performance, or code that’s impossible to maintain.
By spotting these early, you’ll avoid headaches for yourself and anyone else who works on your code!
Pitfall #1: Overusing State & Causing Unwanted Re-renders
Imagine putting every single piece of data into state—your app will re-render any time, even the tiniest value changes. This drains performance and clutters your logic.
What NOT to do:
How to fix:
Directly derive values inside render:
Pitfall #2: Mutating State Directly
If you change objects or arrays inside state without using the updater, React may ignore your changes or break the UI.
Here’s a classic bug:
How to fix:
Always create a new array/object:
Pitfall #3: Dependency Hell with useEffect
It’s easy to end up with infinite loops or missed updates if useEffect dependencies aren’t handled with care.
Best approach: Only include true dependencies, or leave it empty when you want a one-time effect:
And always clean up after yourself:
Pitfall #4: Context and Global State Overuse
Context is powerful—but don’t pour your entire app’s state into it. Large context objects cause unnecessary renders and tangled logic.
Instead:
- Use Context sparingly for truly global stuff (theme, user, locale)
- Keep UI state (like “modal open”) local to components or use reducers for structured updates
Pitfall #5: Memory Leaks From Unfinished Cleanups
Pitfall #6: Over-Engineering & Abstracting Too Early
Bonus: Simple Mistakes to Dodge
- Not using keys in lists:
- Forgetting className (using class by accident)
- Using anonymous functions in JSX, which creates a new function each render:
