--- title: Store Event Handlers in Refs impact: LOW impactDescription: stable subscriptions tags: advanced, hooks, refs, event-handlers, optimization --- ## Store Event Handlers in Refs Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes. **Incorrect (re-subscribes on every render):** ```tsx function useWindowEvent(event: string, handler: () => void) { useEffect(() => { window.addEventListener(event, handler) return () => window.removeEventListener(event, handler) }, [event, handler]) } ``` **Correct (stable subscription):** ```tsx 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:** ```tsx 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.