React Hooks are one of the most important features in modern React. Hooks let us use powerful React features — such as state, effects, context, refs, and more — directly inside function components.
If you are learning React today, Hooks are essential. You will use them in almost every component you build.
This post explains what Hooks are, why they exist, and the most important Hooks we will use, along with simple code examples to help us understand each concept.
🧠 1. What Are Hooks?
Hooks are special functions provided by React that allow function components to use React features.
Before Hooks, React relied heavily on class components for state and lifecycle logic.
Hooks changed that.
✔ Hooks let us use React features in plain function components
✔ Hooks always start with the word use
✔ Hooks are used inside function components or custom hooks
✔ Hooks make React code cleaner and easier to understand
Examples of Hooks:
useStateuseEffectuseRefuseContextuseReduceruseCallbackuseMemo
…and more.
🎯 2. Why Do Hooks Exist?
Hooks were introduced to solve real problems React developers faced:
✔ Add state to function components
Before Hooks, only class components could use state.
✔ Replace lifecycle methods
Like componentDidMount, componentDidUpdate, and componentWillUnmount.
✔ Avoid the complexity of classes
Less boilerplate, more readable code.
✔ Share logic without duplicating code
Custom Hooks help reuse logic across components.
✔ Make components smaller and easier to test
Function components + Hooks are simpler than classes.
🚦 3. Rules of Hooks (Very Important)
React requires two rules:
Rule 1 — Only call Hooks at the top level
❌ Never inside loops
❌ Never inside conditions
❌ Never inside nested functions
✔ Always at the top of your component.
This ensures React can track state consistently across renders.
Rule 2 — Only call Hooks from function components or custom hooks
❌ Not from regular functions
❌ Not from class components
✔ Only call Hooks from:
- a function component
- a custom hook (your own function starting with
use)
These rules ensure predictable behavior.
📘 4. Common Hooks We Will Use Daily
Below are the Hooks used most often in real-world React applications.
Each includes a simple code snippet for easy understanding.
🔹 4.1 useState — Add state to a function component
useState lets you store values that change over time.
const [count, setCount] = useState(0);
count→ current valuesetCount→ function to update it- UI re-renders when state changes
This is the same Hook taught in your State Management post.
🔹 4.2 useEffect — Run side effects
Side effects are things that happen outside the React UI, such as:
- Fetching data
- Setting up timers
- Subscribing to events
- Updating the document title
Example:
useEffect(() => {
console.log("Component mounted");
}, []);
✔ Runs after the component renders
✔ Empty array ([]) means run only once (on mount)
🔹 4.3 useRef — Store values without causing re-renders
Useful for:
- DOM references
- Storing values across renders
- Keeping mutable variables
Example:
const inputRef = useRef<HTMLInputElement>(null);
You can access:
inputRef.current
🔹 4.4 useContext — Access context without prop drilling
Lets you read values from a React context:
const theme = useContext(ThemeContext);
Great for:
- Themes
- Authentication
- User settings
- Any global shared data
🔹 4.5 useReducer — Manage complex state logic
Similar to Redux but built into React.
const [state, dispatch] = useReducer(reducer, initialState);
Useful for:
- Multi-step state updates
- Complex forms
- Business logic
🔹 4.6 useCallback — Memoize functions
Prevents functions from being recreated on every render.
const handleClick = useCallback(() => {
console.log("clicked");
}, []);
Helpful when passing functions to child components.
🔹 4.7 useMemo — Memoize expensive calculations
const result = useMemo(() => expensiveCalculation(value), [value]);
✔ Saves performance
✔ Avoids recalculating unless dependencies change
🔹 4.8 useId — Generate stable unique IDs (React 18)
Useful for accessibility:
const id = useId();
🔹 4.9 useTransition — Improve UI responsiveness (React 18)
Used for marking updates as non-urgent.
const [isPending, startTransition] = useTransition();
Helps keep the UI responsive during heavy updates.
🔹 4.10 useDeferredValue — Defer expensive updates
Lets you delay updates that are not urgent.
const deferredValue = useDeferredValue(value);
Keeps typing and UI interactions fast even with heavy processing.
🎯 5. Advanced Hooks (We Probably Don’t Need Yet)
React also has advanced hooks, mostly used in special cases:
- useLayoutEffect
Runs before the browser paints the screen
Used for layout calculations - useImperativeHandle
Customizes the instance exposed byref - useSyncExternalStore
For external stores (Redux, Zustand) - useDebugValue
Helps debug custom hooks - useInsertionEffect
Special hook for CSS-in-JS libraries
These are not needed for beginners and rarely used.
🛠 6. Custom Hooks — Reuse Logic Across Components
We can create our own hook by writing a function that starts with “use“.
Example:
function useCounter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return { count, increment };
}
Then use it like this:
const { count, increment } = useCounter();
Custom hooks let us reuse logic without duplicating code.
🎉 Final Summary
React Hooks are the modern way to write components.
They let your function components:
- Store state (
useState) - Run side effects (
useEffect) - Access DOM nodes (
useRef) - Share data (
useContext) - Manage complex logic (
useReducer) - Optimize performance (
useMemo,useCallback) - Create reusable logic (custom hooks)
- Improve responsiveness (
useTransition) - Generate unique IDs (
useId)
Hooks make React code cleaner, simpler, and easier to understand.