React is fast, but your code might be slowing it down! Many developers unknowingly make performance mistakes that lead to unnecessary re-renders and sluggish UI updates.
However, blindly applying useMemo
, useCallback
, and useRef
everywhere won't magically optimize your app. In fact, improper usage can make your code harder to maintain without significant performance benefits.
Let's dive into common performance pitfalls in React and how to fix them the right way.
Not a Member? Read for FREE here.
❌ 1. Overusing useMemo
and useCallback
Without Measuring Impact
🚨 The Mistake:
Many developers assume that wrapping every function in useCallback
and every value in useMemo
will automatically improve performance. But the truth is, these hooks should be used selectively.
Example (BAD) ⛔
const ExpensiveComponent = React.memo(({ compute, value }) => {
return <div>Computed Value: {compute(value)}</div>;
});
const ParentComponent = ({ number }) => {
const compute = useCallback((num) => num * 2, []); // ❌ Unnecessary useCallback
return <ExpensiveComponent compute={compute} value={number} />;
};
🚨 Problem: The function is simple, so memoizing it with useCallback
has no measurable benefit.
✅ Correct Approach (Use useCallback
only if necessary)
const ExpensiveComponent = React.memo(({ compute, value }) => {
return <div>Computed Value: {compute(value)}</div>;
});
const ParentComponent = ({ number }) => {
const compute = (num) => num * 2; // ✅ Simpler and clearer
return <ExpensiveComponent compute={compute} value={number} />;
};
🛠 When Should You Use useCallback
and useMemo
?
- When passing functions to memoized components (
React.memo
) - When dealing with expensive calculations
- When dependencies change frequently in useEffect/useCallback
✅ Example Where useMemo
is Actually Helpful:
const sortedData = useMemo(() => heavySortingFunction(data), [data]);
👉 Fix: Don't blindly use useMemo
or useCallback
—use them only if performance profiling shows a benefit.
❌ 2. Using useRef
Instead of useState
for Values That Affect UI
🚨 The Mistake:
Some developers replace useState
with useRef
thinking it will improve performance.
Example (BAD) ⛔
const Counter = () => {
const count = useRef(0); // ❌ Won't trigger re-renders
return (
<div>
<p>Count: {count.current}</p>
<button onClick={() => count.current += 1}>Increment</button>
</div>
);
};
🚨 Problem: useRef
does not trigger UI updates, so the counter won't reflect changes!
✅ Correct Approach: Use useState
for UI updates
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p> {/* ✅ UI updates properly */}
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
🛠 When Should You Use useRef
?
✅ When storing values that should persist across renders but don't need to trigger a re-render.
✅ When referencing DOM elements (useRef
is perfect for handling focus, scroll position, etc.).
✅ Example Where useRef
is Useful:
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus(); // ✅ Works without re-rendering
};
return <input ref={inputRef} />;
👉 Fix: Use useState
when the value affects rendering, and useRef
for non-reactive values.
❌ 3. Ignoring React's Built-in Performance Optimizations
🚨 The Mistake: Many developers forget about React.memo, lazy loading, and Suspense, leading to unnecessary rendering.
✅ Optimize Expensive Components with React.memo
const ExpensiveComponent = React.memo(({ data }) => {
console.log("Re-rendered!");
return <div>{data}</div>;
});
👉 Now, ExpensiveComponent
only re-renders when data
changes.
✅ Lazy Load Heavy Components for Faster Initial Load
const HeavyComponent = React.lazy(() => import("./HeavyComponent"));
return (
<Suspense fallback={<p>Loading...</p>}>
<HeavyComponent />
</Suspense>
);
👉 This improves performance by only loading components when needed.
🚀 Final Thoughts: Measure Before Optimizing!
Many React performance optimizations should be used selectively, not blindly applied everywhere.
✅ Golden Rules for Performance Optimization in React:
✔ Don't overuse useMemo
and useCallback
– measure performance impact first!
✔ Use useRef
only when necessary – don't replace useState
for reactive values.
✔ Optimize rendering with React.memo
and lazy loading when necessary.
✔ Use React Developer Tools to profile performance before optimizing.
💡 What's your biggest React performance lesson? Let's discuss in the comments! 🚀
Key Improvements Based on Feedback:
- Clarified when
useMemo
anduseCallback
are beneficial (not just always use them). - Explained when
useRef
is useful and when it shouldn't replaceuseState
. - Added better examples to illustrate correct usage.
- Encouraged performance measurement instead of premature optimization.
Connect with Me
If you enjoyed this post and would like to stay updated with more content like this, feel free to connect with me on social media:
- Twitter : Follow me on Twitter for quick tips and updates.
- LinkedIn : Connect with me on LinkedIn
- YouTube : Subscribe to my YouTube Channel for video tutorials and live coding sessions.
- Dev.to : Follow me on Dev.to where I share more technical articles and insights.
- WhatsApp : Join my WhatsApp group to get instant notifications and chat about the latest in tech
Email: Email me on dipaksahirav@gmail.com for any questions, collaborations, or just to say hi!
I appreciate your support and look forward to connecting with you!