You've got the tools:
- ✅
useState - ✅
useEffect - ✅
useRef - ✅
useContext,useReducer,useCallback,useMemo - ✅ Even your own
custom hooks
Now pause.
Before you keep stacking hooks like Jenga blocks, let's talk best practices — the difference between clean, scalable code vs. spaghetti React 🍝.
🎯 1. Always Call Hooks at the Top Level
Never put hooks inside:
- Loops
- If/else
- Functions inside JSX
// ❌ Wrong
if (condition) {
const [count, setCount] = useState(0);
}
// ✅ Right
const [count, setCount] = useState(0);
Hooks must run in the same order every time React renders the component.
🛠️ 2. Keep Hook Logic Focused (One Job Per Hook)
Don't cram 10 responsibilities into one useEffect. Split logic by purpose:
useEffect(() => {
// Fetch data
}, []);
useEffect(() => {
// Add event listener
}, []);
🎯 Your hook logic should be focused and clear — like a clean kitchen, not a junk drawer.
🔁 3. Memoize When Needed, Not Always
useMemoanduseCallbackare great.- But overusing them can hurt performance instead of helping.
✅ Use them for:
- Expensive calculations
- Stable callbacks in
React.memochildren - Derived values that affect re-renders
🧹 4. Clean Up Side Effects
If you set up something in useEffect (like a listener or timer), always clean it:
useEffect(() => {
const timer = setTimeout(() => console.log("tick"), 1000);
return () => clearTimeout(timer); // ✅ cleanup
}, []);
Don't let your effects haunt your app. Clean up like a responsible dev ghostbuster 👻.
🪝 5. Start Custom Hooks with use
// ✅ Correct
function useFetch() {}
// ❌ Wrong
function fetchDataHook() {}
React recognizes hooks only if the name starts with
use. Otherwise, it won't track rules like lifecycle and reactivity.
📦 6. Extract Reusable Logic into Custom Hooks
Don't copy-paste useEffect and useState blocks into 10 components.
Extract it:
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return width;
}
✅ Now your logic is reusable, testable, and clean.
💬 7. Don't Use useRef to Replace State
Yes, useRef is cool because it doesn't trigger re-renders.
But don't abuse it for everything.
❌ Don't replace useState if the value affects UI.
✅ Do use useRef for:
- Storing DOM elements
- Timeouts
- Previous values
- API instances
- Silent memory
⚠️ 8. Know When to Use useReducer
If you're tracking a lot of related state or handling complex logic…
const [state, dispatch] = useReducer(reducerFn, initialState);
- ✅ Cleaner than writing 10
useStates - ✅ Better for shared logic between states
🧠 9. Always Declare Dependencies in useEffect
useEffect(() => {
doSomethingWith(name); // ❌ Missing name in deps
}, []);
✅ Fix it:
useEffect(() => {
doSomethingWith(name);
}, [name]);
If you use it inside the effect, declare it.
Otherwise, you might be using stale data and won't even realize.
🔍 10. Use ESLint Rules for Hooks
npm install eslint-plugin-react-hooks
It warns you if you:
- Forget a dependency
- Break the Rules of Hooks
Like a bodyguard for your
useEffect.
✅ Summary – React Hooks Best Practices
| Practice | Why it Matters |
|---|---|
| Call hooks only at top level | Keep the order consistent across renders |
Separate concerns in useEffect |
Easier to debug and scale |
| Memoize only when needed | Avoid premature optimization |
| Clean up side effects | Prevent memory leaks and double firing |
| Use custom hooks for reuse | DRY, clean, and composable logic |
Name hooks with use |
React tracks it properly |
| Declare all effect dependencies | Avoid bugs caused by stale values |
🧠 FAQs – Best Practices for Hooks
1. Should I use hooks in every component?
Only when needed. If your component doesn't need state or side effects, no need for hooks.
2. Can I skip dependencies in useEffect to stop it re-running?
Technically yes. But it's an anti-pattern. Use memoization instead.
3. When should I prefer useReducer over useState?
When your state is complex, dependent, or needs to be shared through logic (like forms or modals).
4. Do custom hooks trigger re-renders?
Not directly. Only the hooks used inside them (like useState) can cause re-renders.
5. Can I use a hook inside a helper function?
No. Hooks must be called directly at the top level of your component or custom hook.
❤️ At Learn Virendana, we love creating high-quality React tutorials that simplify complex concepts and deliver a practical, real-world React learning experience for developers