Install this skill
npx skills add vercel-labs/agent-skillsWorks across Claude Code, Cursor, Codex, Copilot & Antigravity
React effects often trigger re-runs when passed function dependencies update on every render, leading to unnecessary event listener cleanup and re-attachment. By capturing event handlers in a mutable ref, you maintain a stable effect dependency while ensuring the logic executed inside the listener remains current. This pattern prevents performance bottlenecks caused by frequent DOM subscription churn. When updates to state or props pass new function references to a hook, the ref approach decouples the effect lifecycle from the function identity. This ensures listeners attached to global objects like the window or document stay persistent across re-renders, preventing memory leaks or race conditions. For environments supporting recent React versions, this technique acts as a manual implementation of event stability, keeping component side effects predictable and efficient.
When to Use This Skill
- •Creating custom hooks for global window or document events
- •Managing WebSocket message handlers that need access to fresh state
- •Preventing effect loops in components that frequently pass anonymous functions
- •Attaching scroll or resize listeners without constant re-binding
How to Invoke This Skill
Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:
- “My window event listener re-runs on every render
- “How to keep event handlers stable in a useEffect
- “Prevent useEffect from constantly re-attaching listeners
- “Ref pattern for event handler synchronization
- “Stable callback pattern for global browser events
What this skill does
- •Decouples effect execution from handler reference changes
- •Maintains persistent event listeners across re-renders
- •Synchronizes latest handler logic with a stable effect dependency
- •Reduces redundant browser API event cleanup cycles
- •Provides a fallback for stable event logic without experimental APIs
When not to use it
- ✕When the handler logic does not require access to updated component state
- ✕When using React 19+ which natively supports event synchronization patterns
- ✕Simple components where re-subscription performance costs are negligible
Example workflow
- Initialize a useRef to hold the latest version of the handler function
- Create a layout effect or standard effect to sync the ref current value with the provided handler
- Define a secondary effect with an empty dependency array or specific trigger props
- Wrap the actual listener inside the effect to call the handler via the ref
- Return the cleanup function to remove the listener on component unmount
Prerequisites
- –Basic knowledge of React hooks lifecycle
- –Understanding of reference persistence with useRef
Pitfalls & limitations
- !Forgetting to update the ref during renders leads to stale closure bugs
- !Potential for minor race conditions if the ref is accessed after component unmount
- !Overusing refs for logic that should be handled by dependency management
FAQ
How it compares
While manual management involves fragile dependency arrays, this ref-based approach guarantees that effects remain stable even when your handler references change dynamically.
📄 Full skill instructions — original source: vercel-labs/agent-skills
Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes.
**Incorrect (re-subscribes on every render):**
function useWindowEvent(event: string, handler: () => void) {
useEffect(() => {
window.addEventListener(event, handler)
return () => window.removeEventListener(event, handler)
}, [event, handler])
}**Correct (stable subscription):**
function useWindowEvent(event: string, handler: () => void) {
const handlerRef = useRef(handler)
useEffect(() => {
handlerRef.current = handler
}, [handler])
useEffect(() => {
const listener = () => handlerRef.current()
window.addEventListener(event, listener)
return () => window.removeEventListener(event, listener)
}, [event])
}**Alternative: use
useEffectEvent if you're on latest React:**import { useEffectEvent } from 'react'
function useWindowEvent(event: string, handler: () => void) {
const onEvent = useEffectEvent(handler)
useEffect(() => {
window.addEventListener(event, onEvent)
return () => window.removeEventListener(event, onEvent)
}, [event])
}useEffectEvent provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.How to Use This Skill Unit
Option A: Project-Specific (Recommended)
- Click "Download" above
- In your project, create the directory:
.agent/skills/advanced-event-handler-refs/ - Save the file as
SKILL.md - The agent will automatically discover the skill based on its description.
Option B: Global Installation (All Agents)
Save the file to these locations to make it available across all projects:
- Claude Code:
~/.claude/skills/vercel-labs/agent-skills/advanced-event-handler-refs/SKILL.md - Cursor:
~/.cursor/skills/vercel-labs/agent-skills/advanced-event-handler-refs/SKILL.md - Antigravity:
~/.gemini/antigravity/skills/vercel-labs/agent-skills/advanced-event-handler-refs/SKILL.md
🚀 Install with CLI:npx skills add vercel-labs/agent-skills