React is powerful, but even experienced developers fall into common traps that can slow performance and make debugging a nightmare. Letβs explore ten mistakes you should avoid at all costs!
1οΈβ£ Modifying State Directly
Changing state directly instead of using setState
or state setters in hooks can cause unexpected behavior. Always treat state as immutable.
β Bad:
state.count = state.count + 1; // Wrong β
β
Good:
setState(prev => ({ count: prev.count + 1 })); // Correct β
2οΈβ£ Not Using Keys in Lists
React uses keys to track elements efficiently. Skipping keys in .map() can lead to rendering issues.
β Bad:
items.map(item => <li>{item.name}</li>); // No key β
β
Good:
items.map(item => <li key={item.id}>{item.name}</li>); // Correct β
3οΈβ£ Excessive Re-renders
Unnecessary renders can hurt performance. Use useMemo
, useCallback
, and React.memo
when needed.
4οΈβ£ Not Cleaning Up Effects
Forgetting cleanup in useEffect
can cause memory leaks, especially in event listeners and timers.
β
Always cleanup:
useEffect(() => {
const interval = setInterval(() => {
console.log('Running...');
}, 1000);
return () => clearInterval(interval); // Cleanup β
}, []);
5οΈβ£ Using useEffect Unnecessarily
Sometimes, useEffect
is overused for things that can be done without it, like directly setting state in event handlers.
6οΈβ£ Ignoring Dependency Arrays in useEffect
Incorrect dependency arrays can cause infinite loops or missing updates.
β Bad:
useEffect(() => {
fetchData();
}); // No dependency array β
β
Good:
useEffect(() => {
fetchData();
}, [dependency]); // Correct β
7οΈβ£ Using State When a Ref is Better
State updates cause re-renders, but refs donβt. If you donβt need reactivity, use useRef
.
β Bad:
const [count, setCount] = useState(0); // Re-renders on update β
β
Good:
const countRef = useRef(0); // No re-render β
8οΈβ£ Not Handling Asynchronous State Updates
React batches updates, so relying on outdated state can cause bugs.
β Bad:
setCount(count + 1); // Might not update correctly β
setCount(count + 1);
β
Good:
setCount(prev => prev + 1); // Always correct β
setCount(prev => prev + 1);
9οΈβ£ Blocking the UI with Expensive Computations
Heavy calculations in render can slow down the UI. Use useMemo
.
β Bad:
const result = expensiveCalculation(data); // Runs on every render β
β
Good:
const result = useMemo(() => expensiveCalculation(data), [data]); // Optimized β
π Not Handling Errors Properly
Without error boundaries, one crash can break the whole app.
β
Always use an error boundary:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}
Wrap components like this:
<ErrorBoundary>
<MyComponent /> // component name
</ErrorBoundary>
π‘ Did you find these helpful? What other React mistakes have you seen? Share in the comments! π
π‘ Want more React tips? Follow me for weekly posts on writing better React code!
Top comments (3)
thanks, it's so helpful
Thanks, it's helpful
nicely written. It will be helpful for beginners.