react-use-callback
Guides proper usage of the useCallback hook in React. Use this skill when optimizing function references, passing callbacks to memoized components, or preventing unnecessary re-renders.
Best use case
react-use-callback is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Guides proper usage of the useCallback hook in React. Use this skill when optimizing function references, passing callbacks to memoized components, or preventing unnecessary re-renders.
Teams using react-use-callback should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/react-use-callback/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How react-use-callback Compares
| Feature / Agent | react-use-callback | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Guides proper usage of the useCallback hook in React. Use this skill when optimizing function references, passing callbacks to memoized components, or preventing unnecessary re-renders.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# React: useCallback Best Practices
## Core Principle
**useCallback caches a function definition between re-renders until its dependencies change.**
Only use `useCallback` for specific performance optimizations - not by default.
## When to Use useCallback
### 1. Passing Callbacks to Memoized Children
When passing a function to a component wrapped in `memo()`:
```jsx
import { useCallback, memo } from 'react';
const ExpensiveChild = memo(function ExpensiveChild({ onClick }) {
// Expensive rendering logic
return <button onClick={onClick}>Click me</button>;
});
function Parent({ productId }) {
// Without useCallback, handleClick would be a new function every render
// causing ExpensiveChild to re-render unnecessarily
const handleClick = useCallback(() => {
console.log('Clicked:', productId);
}, [productId]);
return <ExpensiveChild onClick={handleClick} />;
}
```
### 2. Function as Effect Dependency
When a function is used inside `useEffect`:
```jsx
function ChatRoom({ roomId }) {
const createOptions = useCallback(() => {
return { serverUrl: 'https://localhost:1234', roomId };
}, [roomId]);
useEffect(() => {
const options = createOptions();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [createOptions]);
}
```
**Better alternative:** Move the function inside the effect:
```jsx
function ChatRoom({ roomId }) {
useEffect(() => {
// Function defined inside effect - no useCallback needed
function createOptions() {
return { serverUrl: 'https://localhost:1234', roomId };
}
const options = createOptions();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
}
```
### 3. Custom Hook Return Values
Always wrap functions returned from custom hooks:
```jsx
function useRouter() {
const { dispatch } = useContext(RouterStateContext);
const navigate = useCallback((url) => {
dispatch({ type: 'navigate', url });
}, [dispatch]);
const goBack = useCallback(() => {
dispatch({ type: 'back' });
}, [dispatch]);
return { navigate, goBack };
}
```
### 4. Reducing State Dependencies
Use updater functions to eliminate state dependencies:
```jsx
// Before: todos is a dependency
const handleAddTodo = useCallback((text) => {
setTodos([...todos, { id: nextId++, text }]);
}, [todos]);
// After: No todos dependency needed
const handleAddTodo = useCallback((text) => {
setTodos(todos => [...todos, { id: nextId++, text }]);
}, []);
```
## When NOT to Use useCallback
### 1. Child Is Not Memoized
Without `memo()`, `useCallback` provides no benefit:
```jsx
// useCallback is pointless here
function Parent() {
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
// Child will re-render anyway when Parent re-renders
return <Child onClick={handleClick} />;
}
```
### 2. Coarse Interactions
Apps with page-level navigation don't benefit from memoization:
```jsx
// Overkill for simple navigation
function App() {
const [page, setPage] = useState('home');
// Not needed - page transitions are inherently expensive anyway
const navigate = useCallback((page) => setPage(page), []);
return <Navigation onNavigate={navigate} />;
}
```
### 3. When Better Alternatives Exist
**Accept JSX as children:**
```jsx
// Instead of memoizing onClick
function Panel({ children }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && children}
</div>
);
}
// Children don't re-render when Panel's state changes
<Panel>
<ExpensiveComponent />
</Panel>
```
**Keep state local:**
```jsx
// Don't lift state higher than necessary
function SearchForm() {
// Local state doesn't trigger parent re-renders
const [query, setQuery] = useState('');
return <input value={query} onChange={e => setQuery(e.target.value)} />;
}
```
## Anti-Patterns to Avoid
### Missing Dependency Array
```jsx
// Returns a new function every render
const handleClick = useCallback(() => {
doSomething();
}); // Missing dependency array!
// Correct
const handleClick = useCallback(() => {
doSomething();
}, []);
```
### useCallback in Loops
```jsx
// Can't call hooks in loops
function List({ items }) {
return items.map(item => {
// WRONG
const handleClick = useCallback(() => sendReport(item), [item]);
return <Chart key={item.id} onClick={handleClick} />;
});
}
// Correct: Extract to component
function List({ items }) {
return items.map(item => (
<Report key={item.id} item={item} />
));
}
function Report({ item }) {
const handleClick = useCallback(() => sendReport(item), [item]);
return <Chart onClick={handleClick} />;
}
// Alternative: Wrap Report in memo instead
const Report = memo(function Report({ item }) {
function handleClick() {
sendReport(item);
}
return <Chart onClick={handleClick} />;
});
```
## useCallback vs useMemo
| Hook | Caches | Use Case |
|------|--------|----------|
| `useCallback(fn, deps)` | The function itself | Callback props |
| `useMemo(() => fn, deps)` | Result of calling function | Computed values |
```jsx
// Equivalent
const memoizedFn = useCallback(fn, deps);
const memoizedFn = useMemo(() => fn, deps);
```
## Quick Reference
### DO
- Use with `memo()` wrapped children
- Use when function is an effect dependency
- Wrap custom hook return functions
- Use updater functions to reduce dependencies
### DON'T
- Add everywhere "just in case"
- Use without `memo()` on child component
- Use when you can restructure code instead
- Forget the dependency array
## Performance Debugging
When memoization isn't working, debug dependencies:
```jsx
const handleSubmit = useCallback((orderDetails) => {
// ...
}, [productId, referrer]);
console.log([productId, referrer]);
```
Check in browser console:
```js
Object.is(temp1[0], temp2[0]); // First dependency same?
Object.is(temp1[1], temp2[1]); // Second dependency same?
```
## Future: React Compiler
React Compiler automatically memoizes values and functions, reducing the need for manual `useCallback` calls. Consider using the compiler to handle memoization automatically.
## References
- [React Docs - useCallback](https://react.dev/reference/react/useCallback)
- [React Docs - memo](https://react.dev/reference/react/memo)
- [React Docs - useMemo](https://react.dev/reference/react/useMemo)Related Skills
react-useeffect-avoid
Guides when NOT to use useEffect and suggests better alternatives. Use when reviewing React code, troubleshooting performance, or considering useEffect for derived state or form resets.
react-use-state
Guides proper usage of React useState hook. Use this skill when adding state to components, deciding between useState vs alternatives, or troubleshooting state update issues.
react-use-client-boundary
Guides proper usage of "use client" directive in React/Next.js. Use this skill when adding client components, troubleshooting Server Component errors, or deciding where to place the client boundary.
react-key-prop
Guides proper usage of the key prop in React lists. Use this skill when rendering lists, mapping arrays to components, or troubleshooting list-related state bugs.
what-not-to-do-as-product-manager
Anti-patterns and mistakes to avoid as a product manager. Use when evaluating leadership behaviors, improving team dynamics, reflecting on management practices, or onboarding new product managers.
visual-cues-cta-psychology
Design effective CTAs using visual attention and gaze psychology principles. Use when designing landing pages, button hierarchies, conversion elements, or optimizing user attention flow through interfaces.
vercel-sandbox
Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.
value-realization
Analyze if end users discover clear value. Use when evaluating product concepts, analyzing adoption, or uncertain about direction.
user-story-fundamentals
Capture requirements from user perspective with structured user stories. Use when writing backlog items, defining acceptance criteria, prioritizing features, or communicating requirements between product and development.
typescript-satisfies-operator
Guides proper usage of TypeScript's satisfies operator vs type annotations. Use this skill when deciding between type annotations (colon) and satisfies, validating object shapes while preserving literal types, or troubleshooting type inference issues.
typescript-interface-vs-type
Guides when to use interface vs type in TypeScript. Use this skill when defining object types, extending types, or choosing between interface and type aliases.
typescript-best-practices
Guides TypeScript best practices for type safety, code organization, and maintainability. Use this skill when configuring TypeScript projects, deciding on typing strategies, writing async code, or reviewing TypeScript code quality.