--- title: Store Event Handlers in Refs impact: LOW impactDescription: 稳定的订阅 tags: advanced, hooks, refs, event-handlers, optimization --- ## 将事件处理函数存储在 Refs 中 当回调函数被用于那些不应因回调变化而重新订阅的 effect 时,应将回调存储在 ref 中。 **错误做法(每次渲染都重新订阅):** ```tsx function useWindowEvent(event: string, handler: (e) => void) { useEffect(() => { window.addEventListener(event, handler) return () => window.removeEventListener(event, handler) }, [event, handler]) } ``` **正确做法(稳定的订阅):** ```tsx function useWindowEvent(event: string, handler: (e) => void) { const handlerRef = useRef(handler) useEffect(() => { handlerRef.current = handler }, [handler]) useEffect(() => { const listener = (e) => handlerRef.current(e) window.addEventListener(event, listener) return () => window.removeEventListener(event, listener) }, [event]) } ``` **替代方案:如果你在使用最新版 React,可以使用 `useEffectEvent`:** ```tsx import { useEffectEvent } from 'react' function useWindowEvent(event: string, handler: (e) => void) { const onEvent = useEffectEvent(handler) useEffect(() => { window.addEventListener(event, onEvent) return () => window.removeEventListener(event, onEvent) }, [event]) } ``` `useEffectEvent` 为同一模式提供了更简洁的 API:它创建一个稳定的函数引用,始终调用最新版本的处理函数。