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 (0)