Hooks are special React functions that allow Functional Components to use React features such as:
Before Hooks (React <16.8), these features required Class Components.
After Hooks:
Functional Components
↓
Hooks
↓
Modern React Development
Hooks are functions that start with:
use
Examples:
Without Hooks:
this KeywordWith Hooks:
Only call Hooks at the top level.
Good:
function App() {
const [
count,
setCount
] = useState(0);
}
Bad:
if (true) {
useState(0);
}
Only call Hooks inside:
The two most commonly used hooks are:
These appear in almost every React application.
useState allows a component to store and update data.
import {
useState
}
from "react";
const [
state,
setState
] = useState(initialValue);
import {
useState
}
from "react";
function Counter() {
const [
count,
setCount
] = useState(0);
return (
<button
onClick={() =>
setCount(
count + 1
)
}
>
{count}
</button>
);
}
Initial state:
count = 0
After clicking:
1
2
3
...
User Click
↓
setCount()
↓
State Changes
↓
Component Re-renders
↓
UI Updates
const [
name,
setName
] = useState("");
const [
age,
setAge
] = useState(21);
const [
user,
setUser
] = useState({
name: "Samir",
age: 21
});
Update:
setUser({
...user,
age: 22
});
useEffect handles side effects.
Anything outside rendering.
Examples:
import {
useEffect
}
from "react";
useEffect(() => {
}, []);
useEffect(() => {
console.log(
"Component Mounted"
);
}, []);
Runs only once.
useEffect(() => {
console.log(
"Rendered"
);
});
Runs after every render.
useEffect(() => {
console.log(
count
);
}, [count]);
Runs whenever:
count
changes.
useEffect(() => {
const timer =
setInterval(() => {
}, 1000);
return () => {
clearInterval(
timer
);
};
}, []);
Cleanup runs when the component unmounts.
Mount
↓
Run Effect
↓
Update
↓
Run Effect Again
↓
Unmount
↓
Cleanup
React provides several commonly used hooks:
Stores mutable values without causing re-renders.
Often used for DOM access.
import {
useRef
}
from "react";
const inputRef =
useRef(null);
<input
ref={inputRef}
/>
inputRef.current
Returns:
<input />
function App() {
const inputRef =
useRef(null);
return (
<>
<input
ref={inputRef}
/>
<button
onClick={() =>
inputRef.current.focus()
}
>
Focus
</button>
</>
);
}
| useRef | useState |
|---|---|
| No Re-render | Causes Re-render |
| Mutable | Reactive |
| DOM Access | UI State |
Provides global state without prop drilling.
App
↓
Parent
↓
Child
↓
GrandChild
Passing props through many levels becomes difficult.
Context
↓
Any Component
can access data directly.
import {
createContext
}
from "react";
const UserContext =
createContext();
<UserContext.Provider
value="Samir"
>
<App />
</UserContext.Provider>
const user =
useContext(
UserContext
);
Output:
Samir
Memoizes expensive calculations.
Prevents unnecessary recomputation.
const total =
calculateLargeData();
Runs every render.
const total =
useMemo(() => {
return calculateLargeData();
}, [data]);
Only recalculates when:
data
changes.
const doubled =
useMemo(() => {
return count * 2;
}, [count]);
Render
↓
Dependencies Changed?
↓
Yes → Recalculate
No → Use Cached Value
Memoizes functions.
Every render creates a new function.
const handleClick = () => {
};
const handleClick =
useCallback(() => {
console.log(
"Clicked"
);
}, []);
The function remains the same between renders.
Useful when passing functions to child components.
Example:
<Child
onClick={handleClick}
/>
Prevents unnecessary re-renders.
| Hook | Memoizes |
|---|---|
| useMemo | Value |
| useCallback | Function |
An alternative to useState for complex state.
import {
useReducer
}
from "react";
function reducer(
state,
action
) {
switch (
action.type
) {
case "increment":
return {
count:
state.count + 1
};
default:
return state;
}
}
const [
state,
dispatch
] = useReducer(
reducer,
{
count: 0
}
);
dispatch({
type: "increment"
});
function Counter() {
const [
state,
dispatch
] = useReducer(
reducer,
{
count: 0
}
);
return (
<button
onClick={() =>
dispatch({
type: "increment"
})
}
>
{state.count}
</button>
);
}
| useState | useReducer |
|---|---|
| Simple State | Complex State |
| Easier | More Structured |
| Small Components | Large Components |
Advanced hooks are commonly used for:
Examples:
Custom Hooks allow reusable React logic.
They prevent repeating the same logic across multiple components.
Without a custom hook:
must be repeated everywhere.
Hook names must start with:
use
Example:
function useCounter() {
const [
count,
setCount
] = useState(0);
const increment = () => {
setCount(
prev => prev + 1
);
};
return {
count,
increment
};
}
function App() {
const {
count,
increment
} = useCounter();
}
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;
}
Usage:
const width =
useWindowWidth();
Good:
const [
count
] = useState(0);
Bad:
if (condition) {
useState(0);
}
const [
name,
setName
] = useState("");
Ideal for:
useEffect(() => {
const timer =
setInterval(() => {
}, 1000);
return () => {
clearInterval(
timer
);
};
}, []);
Bad:
const value =
useMemo(
() => count + 1,
[count]
);
This optimization is unnecessary.
Use useMemo only for expensive calculations.
Bad:
const handleClick =
useCallback(() => {
}, []);
Avoid wrapping every function.
Use it only when optimization is actually needed.
Good examples:
| Scenario | Hook |
|---|---|
| Simple State | useState |
| API Calls | useEffect |
| DOM Access | useRef |
| Global Data | useContext |
| Expensive Calculation | useMemo |
| Stable Function | useCallback |
| Complex State | useReducer |
| Shared Logic | Custom Hook |
Login Page
↓
useState
(Form Fields)
↓
useEffect
(API Call)
↓
useContext
(User Data)
↓
useRef
(Focus Input)
↓
useMemo
(Filter Results)
↓
useCallback
(Button Handlers)
| Hook | Purpose |
|---|---|
| useState | Manage State |
| useEffect | Side Effects |
| useRef | DOM Access / Mutable Values |
| useContext | Global State |
| useMemo | Cache Values |
| useCallback | Cache Functions |
| useReducer | Complex State |
| Custom Hooks | Reusable Logic |
Hooks are the foundation of modern React.
State
↓
useState
Side Effects
↓
useEffect
DOM Access
↓
useRef
Global Data
↓
useContext
Performance
↓
useMemo
↓
useCallback
Complex Logic
↓
useReducer
Reusability
↓
Custom Hooks
Almost every React application—from a simple counter to a large-scale Next.js dashboard—relies heavily on Hooks for state management, side effects, performance optimization, and code reuse.