1. Introduction đ
Hooks transformed how developers write React applications by allowing function components to use state, side effects, and other React features without writing a class. This tutorial provides a comprehensive tour of React's built-in Hooks, custom Hooks, and the rules that govern how they work.
Information
2. What are Hooks? đ¤
Hooks are special functions, always prefixed with use, that let function components "hook into" React features like state, context, and lifecycle behavior.
Code Snippet
import { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => setSeconds((s) => s + 1), 1000);
return () => clearInterval(interval);
}, []);
return <p>Elapsed: {seconds}s</p>;
}3. Why Hooks? đĄ
- Simpler Components: No need for class syntax, this binding, or constructors.
- Reusable Logic: Custom Hooks let you extract and share stateful logic between components.
- Better Organization: Related logic can be grouped together, instead of split across lifecycle methods.
- Easier Testing: Function components with Hooks are generally simpler to test in isolation.
4. History of Hooks đ
5. Rules of Hooks âī¸
Hooks rely on being called in a consistent order on every render, so React must follow strict rules to track each Hook's state correctly.
- Only call Hooks at the top level of a function component or custom Hook.
- Never call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React function components or other custom Hooks â never from regular JavaScript functions.
â Invalid â Hook Inside a Condition
function Bad({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // â Breaks the rules of Hooks
}
}Danger
6. Hook Naming Convention đˇī¸
Every Hook â built-in or custom â must start with the prefix use. This convention allows both React and linting tools to recognize and enforce the Rules of Hooks.
Code Snippet
// Built-in Hooks
useState(), useEffect(), useContext()
// Custom Hooks
useAuth(), useFetch(), useLocalStorage()Best Practice
7. Built-in Hooks Overview đ
| Category | Hooks |
|---|---|
| State | useState, useReducer |
| Effect | useEffect, useLayoutEffect, useInsertionEffect |
| Context | useContext |
| Ref | useRef, useImperativeHandle |
| Performance | useMemo, useCallback |
| Concurrent | useTransition, useDeferredValue |
| Escape Hatch | useDebugValue, useId, useSyncExternalStore |
| Server / Actions | use, useActionState, useOptimistic |
8. State Hooks đ§
Code Snippet
const [count, setCount] = useState(0);Manages a single piece of state, ideal for simple values.
Code Snippet
function reducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "decrement": return { count: state.count - 1 };
default: return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });Manages complex state logic with multiple sub-values or transitions, similar to a mini Redux reducer.
Tip
9. Effect Hooks đ
Effect Hooks let components synchronize with external systems â APIs, subscriptions, timers, or the DOM â outside of React's normal rendering flow.
Code Snippet
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then((res) => res.json())
.then(setData);
return () => controller.abort(); // cleanup
}, []); // dependency array| Hook | Timing |
|---|---|
| useEffect | Runs after the browser paints the screen |
| useLayoutEffect | Runs synchronously before the browser paints |
| useInsertionEffect | Runs before DOM mutations, mainly for CSS-in-JS libraries |
Warning
10. Context Hooks đ
useContext lets a component read values from a Context Provider higher up the tree, without manually passing props through every intermediate level.
Code Snippet
const ThemeContext = createContext("light");
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click Me</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}Note
11. Ref Hooks đ
useRef creates a mutable container that persists across renders without triggering a re-render when it changes â commonly used to access DOM nodes directly.
Code Snippet
function TextInput() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}Tip
12. Performance Hooks âĄ
Code Snippet
const sortedList = useMemo(
() => [...items].sort((a, b) => a.value - b.value),
[items]
);Memoizes an expensive computed value, recalculating only when its dependencies change.
Code Snippet
const handleClick = useCallback(() => {
console.log("Clicked:", id);
}, [id]);Memoizes a function reference itself, useful when passing callbacks to memoized child components.
Caution
13. Concurrent Hooks đ
Introduced with Concurrent React, these Hooks help keep the UI responsive during expensive updates by controlling update priority.
useTransition
function SearchResults() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState("");
function handleChange(e) {
const value = e.target.value;
startTransition(() => {
setQuery(value); // marked as a low-priority update
});
}
return (
<>
<input onChange={handleChange} />
{isPending && <span>Updating...</span>}
</>
);
}Information
14. Escape Hatch Hooks đĒ
| Hook | Purpose |
|---|---|
| useId | Generates unique, stable IDs for accessibility attributes across server and client renders. |
| useSyncExternalStore | Safely subscribes to external, non-React state sources (e.g., browser APIs, third-party stores). |
| useDebugValue | Displays a custom label for a custom Hook in React Developer Tools. |
Code Snippet
function FormField({ label }) {
const id = useId();
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} />
</>
);
}15. Server Hooks đĨī¸
React 19 introduced Hooks designed for working with Server Components, async data, and form Actions.
use()
function Profile({ userPromise }) {
const user = use(userPromise); // unwraps a Promise
return <h1>{user.name}</h1>;
}useActionState
function SubscribeForm() {
const [state, formAction] = useActionState(subscribeAction, { error: null });
return (
<form action={formAction}>
<input name="email" type="email" />
<button type="submit">Subscribe</button>
{state.error && <p>{state.error}</p>}
</form>
);
}Note
16. Experimental Hooks đ§Ē
React occasionally ships Hooks under experimental or newly stabilized status, refining APIs based on real-world feedback before wide adoption.
- useOptimistic â Shows an optimistic UI state while an async action is still in progress.
- useFormStatus â Reads the pending status of the nearest parent <form>.
Caution
17. Custom Hooks đ ī¸
A custom Hook is simply a JavaScript function, prefixed with use, that calls other Hooks internally to encapsulate and share reusable logic.
useLocalStorage.js
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Usage
function App() {
const [theme, setTheme] = useLocalStorage("theme", "light");
}18. Hook Composition đ§Š
Custom Hooks can call other custom Hooks, allowing complex logic to be built up from smaller, focused pieces.
Code Snippet
function useAuthenticatedFetch(url) {
const { token } = useAuth();
const data = useFetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
return data;
}Tip
19. Sharing Logic with Hooks đ
Before Hooks, sharing stateful logic between components required patterns like higher-order components or render props, which often led to deeply nested component trees. Custom Hooks solve this far more elegantly.
| Old Pattern | Hooks Equivalent |
|---|---|
| Higher-Order Components | Custom Hooks with shared logic |
| Render Props | Custom Hooks returning values directly |
| Mixins (legacy) | Custom Hooks composed together |
20. Hook Execution Order đĸ
React relies on Hooks being called in the exact same order on every render to correctly associate each Hook call with its internal state.
Code Snippet
function Component() {
const [a, setA] = useState(0); // Hook 1
const [b, setB] = useState(0); // Hook 2
useEffect(() => {}, []); // Hook 3
// Order must remain identical on every render
}Important
21. Hook Lifecycle âŗ
Function components don't have explicit lifecycle methods, but useEffect can replicate similar behavior by combining its dependency array with a cleanup function.
| Class Lifecycle | Hook Equivalent |
|---|---|
| componentDidMount | useEffect(() => {...}, []) |
| componentDidUpdate | useEffect(() => {...}, [dep]) |
| componentWillUnmount | Cleanup function returned from useEffect |
22. Hook Dependency Rules đ
Hooks like useEffect, useMemo, and useCallback accept a dependency array that tells React when to re-run the logic.
Code Snippet
useEffect(() => {
console.log("Runs on every render");
});
useEffect(() => {
console.log("Runs only once, on mount");
}, []);
useEffect(() => {
console.log("Runs when 'count' changes");
}, [count]);Warning
23. Common Hook Patterns đ¨
- Data Fetching: useFetch(url) encapsulating loading, error, and data state.
- Debouncing: useDebounce(value, delay) for search inputs.
- Media Queries: useMediaQuery(query) for responsive logic in JS.
- Previous Value Tracking: usePrevious(value) using useRef internally.
- Toggle State: useToggle(initialValue) for simple boolean flags.
A Simple useToggle Hook
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => setValue((v) => !v), []);
return [value, toggle];
}24. Hook Limitations â ī¸
- Hooks cannot be used inside class components.
- Hooks cannot be called conditionally or inside loops (with the notable exception of use()).
- Custom Hooks share logic, not state â each component calling a custom Hook gets its own independent state.
- Overusing Hooks like useEffect for non-side-effect logic can lead to unnecessary complexity.
Note
25. Hook Best Practices đ
- Follow the Rules of Hooks strictly, enforced via eslint-plugin-react-hooks.
- Keep useEffect dependency arrays accurate and complete.
- Extract reusable logic into custom Hooks rather than duplicating it across components.
- Prefer useReducer over multiple useState calls for complex, interrelated state.
- Avoid overusing useMemo/useCallback for trivial computations.
- Always clean up effects that create subscriptions, timers, or listeners.
26. Common Hook Mistakes đĢ
- Calling Hooks conditionally or inside loops, violating the Rules of Hooks.
- Omitting dependencies from useEffect's array, causing stale closures.
- Forgetting cleanup functions, leading to memory leaks from lingering subscriptions or timers.
- Using useEffect for logic that could be computed directly during render (derived state).
- Creating infinite render loops by updating state inside useEffect without proper dependencies.
Danger
27. Frequently Asked Questions â
Question
Answer
Question
Answer
Question
Answer
28. Summary đ
Hooks unified how React components manage state, side effects, and shared logic, replacing older patterns like class lifecycle methods and higher-order components. From foundational Hooks like useState and useEffect to advanced concurrent and server-oriented Hooks, mastering this system unlocks the full power of modern React development.