react-usecallback
React useCallback
Overview
useCallback memoizes function references between renders. In 2026 with React Compiler, manual useCallback is rarely needed — the compiler auto-memoizes. Without the compiler, useCallback only helps when paired with memo() on the child component.
With React Compiler (2025+)
React Compiler 1.0 (Oct 2025) auto-applies memoization at build time. Don't add new useCallback — the compiler handles it better. If memoization is unnecessary, the compiler omits it from output.
Exceptions where manual useCallback is still needed:
- External libraries not compiled by React Compiler (older react-hook-form, animation libs)
- Functions used as
useEffectdependencies that can't be moved inside the effect - Custom hooks exporting functions — wrap in useCallback for stable references
- Measured performance issues the compiler doesn't fix
Without React Compiler
useCallback only makes sense together with memo() on the child component.
// ❌ useCallback without memo = dead code
function Parent() {
const handleClick = useCallback(() => {
console.log('click');
}, []);
return <Child onClick={handleClick} />;
// Child re-renders anyway because Parent re-renders
}
// ✅ useCallback + memo = Child skips re-render
const Child = memo(function Child({ onClick }) {
return <button onClick={onClick}>Click</button>;
});
function Parent() {
const handleClick = useCallback(() => {
console.log('click');
}, []);
return <Child onClick={handleClick} />;
// Child does NOT re-render — handleClick has stable reference
}
Valid Use Cases
1. useEffect dependency
const fetchData = useCallback(async () => {
const data = await fetch('/api/users');
}, []);
useEffect(() => {
fetchData();
}, [fetchData]); // stable reference = runs once
2. Custom hook exports
function useCart() {
const [items, setItems] = useState([]);
// ✅ Stable references for hook consumers
const addItem = useCallback((item) => {
setItems(prev => [...prev, item]);
}, []);
return { items, addItem };
}
3. Context provider functions
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const logout = useCallback(() => setUser(null), []);
const value = useMemo(() => ({ user, logout }), [user, logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
Decision
| Question | Answer |
|---|---|
| Using React Compiler? | Don't add useCallback manually |
Passing fn to memo()'d child? |
✅ useCallback |
| Function in useEffect deps? | ✅ useCallback (or move fn inside effect) |
| Exporting fn from custom hook? | ✅ useCallback |
| Event handler without memo on child? | ❌ Skip — it's dead code |
Common Mistake
The most over-used pattern: wrapping every event handler in useCallback "for performance" without memo on the child. The React docs say explicitly: use useCallback only for performance optimization, not as a default way to declare functions.
References
- useCallback — React docs — official API reference with usage examples and caveats
- Understanding useMemo and useCallback — Josh Comeau's deep dive on when memoization actually helps
- React Compiler — official guide on how React Compiler replaces manual useCallback
More from b4r7x/agent-skills
react-design-patterns
Use when choosing a React component pattern — custom hooks, control props, compound components, headless components, render props, container/presentational, or other architectural patterns. Includes 13 patterns with decision guide and 2025 popularity ranking.
26human-commit
Generates human-like git commit messages based on staged or unstaged changes. Reads git diff, analyzes what changed, and outputs 3 natural commit message options that sound like they were written by a developer — not AI. This skill should be used when the user wants a commit message, asks "what should I write for commit", "generate commit message", "human like commit", "wiadomość do commita", or just asks for help committing.
24humanize-readme
Rewrites a README.md to remove AI slop — buzzwords, generic openers, fake enthusiasm, and formulaic structure — replacing it with direct, honest, human-sounding writing. This skill should be used when the user wants to humanize a README, remove AI-generated writing patterns, make documentation sound less like ChatGPT wrote it, or asks to "fix the README", "humanize readme", "remove AI slop", "make it sound human".
24improve-prompt
Transforms a rough, unpolished prompt idea into a precise, structured AI coding prompt. Automatically researches the current project context (stack, file structure, conventions, git history) before generating. This skill should be used when the user provides a vague or "dirty" prompt idea and asks to refine, improve, or rewrite it — e.g. "improve this prompt", "refine my prompt", "ulepszony prompt", "dopracuj prompt", or simply describes what they want done in rough terms.
23react-anti-patterns
Use when reviewing React code — especially AI-generated code — to catch common anti-patterns. Covers 18 anti-patterns with detection difficulty, including stale closures, state mutation, useEffect abuse, and boolean explosion.
21deep-plan
Takes a rough, unpolished prompt idea and autonomously turns it into an implementation plan. Researches the project deeply, asks clarifying questions, generates a precise internal prompt, then executes it to produce a structured plan with todos. Designed for plan mode. Use when the user gives a vague feature request, rough idea, or "dirty" prompt and wants a ready-to-execute implementation plan — e.g. "plan this", "deep plan", "turn this into a plan", "zaplanuj to", "zrób plan".
19