Mastering React Hooks Rules: From Basics to Expert-Level
React Hooks are one of the most powerful features in React, allowing us to reuse stateful logic elegantly. But with great power comes strict rules. Breaking them leads to confusing errors — the kind that make you scratch your head at 2 AM.
In this blog, we’ll go deep into the Rules of Hooks, explore what to do and what not to do, and finish with expert tips so you can write bulletproof React code.
🔹 What Are Hooks?
Hooks are special JavaScript functions (like useState
, useEffect
, useContext
) that let you "hook into" React’s internal features.
✅ They are always prefixed with use
.
✅ They must be called while React is rendering a functional component.
🔹 The Two Golden Rules of Hooks
1. Call Hooks at the Top Level
Never call Hooks inside loops, conditions, nested functions, or try/catch
.
✔️ Good:
function Counter() {
const [count, setCount] = useState(0); // ✅ Always at the top
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
❌ Bad:
function Bad({ cond }: { cond: boolean }) {
if (cond) {
const theme = useContext(ThemeContext); // 🔴 Wrong: inside a condition
}
}
2. Call Hooks Only from React Functions
Hooks should only be called:
- From React functional components
- From Custom Hooks
✔️ Good:
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
return width;
}
❌ Bad:
function randomUtility() {
const [online, setOnline] = useState(true); // 🔴 Wrong: not a component or custom hook
}
🔹 Common Mistakes (and How to Fix Them)
Here are classic pitfalls developers face:
- ❌ Inside conditionals:
if (loggedIn) {
const user = useState(null); // ❌ Wrong
}
✔️ Fix: Move it to the top of the component.
- ❌ Inside loops:
for (let i = 0; i < 3; i++) {
const theme = useContext(ThemeContext); // ❌ Wrong
}
✔️ Fix: Call it once at the top.
- ❌ Inside event handlers:
function handleClick() {
const theme = useContext(ThemeContext); // ❌ Wrong
}
✔️ Fix: Move hook call outside the handler.
- ❌ Inside class components:
class Bad extends React.Component {
render() {
useEffect(() => {}); // ❌ Wrong
}
}
✔️ Fix: Rewrite as a functional component.
- ❌ Inside
useMemo
/useReducer
callbacks:
const style = useMemo(() => {
const theme = useContext(ThemeContext); // ❌ Wrong
return createStyle(theme);
}, []);
✔️ Fix: Call useContext
outside of useMemo
.
- ❌ Inside
try/catch
:
try {
const [x, setX] = useState(0); // ❌ Wrong
} catch {
const [y, setY] = useState(1); // ❌ Wrong
}
✔️ Fix: Always call hooks unconditionally at the top level.
🔹 Tooling: Catch Errors Early
Use the ESLint plugin eslint-plugin-react-hooks
to detect violations automatically:
npm install eslint-plugin-react-hooks --save-dev
.eslintrc.json
:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}
🔹 Why These Rules Exist?
React relies on the order of Hook calls.
If you call hooks conditionally, React cannot guarantee which state belongs to which call, causing bugs that are nearly impossible to debug.
By enforcing these rules:
- Hooks always run in the same order.
- React can track state consistently across renders.
🔹 Pro Tips for Experts 🚀
- ✅ Use custom hooks to encapsulate shared logic (
useAuth
,useFetch
, etc.) - ✅ Combine Hooks with TypeScript interfaces for type safety.
- ✅ Prefer null unions (
User | null
) when a state may not exist yet. - ✅ Use conditional rendering instead of conditional hook calls.
🏁 Conclusion
Hooks are a game-changer — but only when you respect their rules.
By always calling hooks at the top level and only inside React functions, you ensure your components stay predictable, type-safe, and production-ready.
Next time you hit an error like:
“Invalid hook call”
...chances are, you broke one of these rules.
Stay disciplined, and your React + TypeScript apps will be clean, robust, and easy to scale.
✍️ Written by: Cristian Sifuentes — Full-stack developer & AI/JS enthusiast, passionate about scaling architectures and teaching dev teams how to thrive in the modern JS ecosystem.
✅ Tags: #react
#typescript
#frontend
#programming
Top comments (1)
Nice post! Your breakdown of React Hook rules is spot on, especially the emphasis on calling hooks at the top level and avoiding loops or conditions. This is a common pitfall that can lead to confusing errors.