State Hooks
useState
- Adds local state to a component.
- State updates trigger re-render.
- Setter accepts:
- Direct value
- Updater function
- Updates are async and batched.
const [count, setCount] = useState(0);
setCount(count + 1);
setCount(prev => prev + 1);
useReducer
- Alternative to
useState for complex logic.
- Centralizes updates in reducer function.
- Good for nested state and state machines.
type Action =
| { type: 'inc' }
| { type: 'dec' };
function reducer(state: number, action: Action) {
switch (action.type) {
case 'inc':
return state + 1;
case 'dec':
return state - 1;
default:
return state;
}
}
const [count, dispatch] = useReducer(reducer, 0);
dispatch({ type: 'inc' });
Effect Hooks
useEffect
- Runs side effects after render.
- Used for:
- Fetching
- Timers
- Subscriptions
- DOM sync
- Cleanup runs:
- Before next effect
- On unmount
useEffect(() => {
const id = setInterval(() => {
console.log('tick');
}, 1000);
return () => clearInterval(id);
}, []);
Dependencies
useEffect(() => {}, []); // once
useEffect(() => {}, [value]); // when value changes
useEffect(() => {}); // every render
Abort Fetch
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', {
signal: controller.signal
});
return () => controller.abort();
}, []);
useLayoutEffect
- Like
useEffect but runs:
- Synchronously
- Before browser paint
- Use for layout measurement.
- Blocks paint → use sparingly.
useLayoutEffect(() => {
const height = ref.current?.offsetHeight;
console.log(height);
}, []);
useInsertionEffect
- Runs before DOM mutations.
- Mainly for CSS-in-JS libraries.
- Rare in application code.
useInsertionEffect(() => {
// inject styles
}, []);
Ref Hooks
useRef
- Stores mutable value without re-render.
- Common uses:
- DOM refs
- Timer IDs
- Previous values
- Instance variables
const inputRef = useRef<HTMLInputElement>(null);
inputRef.current?.focus();
Mutable Storage
const countRef = useRef(0);
countRef.current++;
useImperativeHandle
- Customizes exposed
ref API.
- Usually used with
forwardRef.
type InputHandle = {
focus: () => void;
};
const CustomInput = forwardRef<InputHandle>((props, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus() {
inputRef.current?.focus();
}
}));
return <input ref={inputRef} />;
});
Context Hooks
useContext
- Reads nearest context value.
- Re-renders when context changes.
const ThemeContext = createContext('light');
const theme = useContext(ThemeContext);
Provider
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
useMemo
- Memoizes computed value.
- Avoids expensive recalculation.
- Optimization hint only.
const sorted = useMemo(() => {
return items.sort(compare);
}, [items]);
useCallback
- Memoizes function reference.
- Useful for:
- Stable props
- Dependency arrays
- Preventing child re-renders
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
Equivalent
useMemo(() => fn, deps);
memo
- Memoized component.
- Skips re-render if props unchanged.
const Child = memo(function Child({ value }) {
return <div>{value}</div>;
});
Custom Comparison
memo(Component, (prev, next) => {
return prev.id === next.id;
});
Concurrent / Scheduling Hooks
useTransition
- Marks updates as non-urgent.
- Keeps UI responsive during heavy renders.
const [isPending, startTransition] = useTransition();
startTransition(() => {
setSearch(query);
});
Good For
- Filtering
- Navigation
- Large lists
useDeferredValue
- Defers updating a value.
- Helps avoid laggy UI.
const deferredQuery = useDeferredValue(query);
Common Uses
ID Hook
useId
- Generates stable unique IDs.
- Safe for SSR + hydration.
const id = useId();
<label htmlFor={id}>Name</label>
<input id={id} />
External Store Hook
useSyncExternalStore
- Subscribes to external stores safely.
- Prevents tearing in concurrent rendering.
const value = useSyncExternalStore(
store.subscribe,
store.getSnapshot
);
Used By
- Redux
- Zustand
- Custom stores
React 19 Hooks
use
- Reads:
- Promises
- Context
- Resources
- Suspends while waiting.
Promise Example
const data = use(fetchData());
Context Example
const theme = use(ThemeContext);
Works In
- Server Components
- Client Components
useActionState
- Manages async action state.
- Common with forms and server actions.
const [state, formAction, pending] =
useActionState(async (prevState, formData) => {
return {
success: true
};
}, initialState);
<form action={formAction}>
<button disabled={pending}>
Submit
</button>
</form>
useOptimistic
- Optimistic UI updates before server confirmation.
const [optimisticTodos, addOptimisticTodo] =
useOptimistic(todos, (state, newTodo) => [
...state,
newTodo
]);
Usage
addOptimisticTodo(todo);
Good For
- Reads parent form submission status.
- Must be inside form subtree.
const { pending } = useFormStatus();
<button disabled={pending}>
Submit
</button>
Useful With
- Server actions
- Progressive enhancement
Custom Hooks
Rules
- Must start with
use.
- Can call other hooks.
- Reuse stateful logic.
function useCounter() {
const [count, setCount] = useState(0);
const inc = () => setCount(c => c + 1);
return { count, inc };
}
Usage
const { count, inc } = useCounter();
Rules of Hooks
Only Call Hooks
- At top level.
- Inside React components.
- Inside custom hooks.
❌ Invalid
if (condition) {
useEffect(() => {});
}
✅ Valid
useEffect(() => {
if (condition) {
// logic
}
}, [condition]);
Common Patterns
Previous Value
function usePrevious<T>(value: T) {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
Stable Event Callback
const onClick = useCallback(() => {
doSomething(id);
}, [id]);
Fetch Pattern
useEffect(() => {
let ignore = false;
async function load() {
const res = await fetch('/api/data');
const data = await res.json();
if (!ignore) {
setData(data);
}
}
load();
return () => {
ignore = true;
};
}, []);
Hooks Decision Guide
| Need | Hook |
|---|
| Local state | useState |
| Complex state | useReducer |
| Side effects | useEffect |
| DOM access | useRef |
| Shared state | useContext |
| Expensive computation | useMemo |
| Stable callback | useCallback |
| Non-blocking update | useTransition |
| Deferred rendering | useDeferredValue |
| External store | useSyncExternalStore |
| Async resource reading | use |
| Optimistic updates | useOptimistic |
| Form action state | useActionState |
| Form pending status | useFormStatus |