[ PROMPT_NODE_25200 ]
client-event-listeners
[ SKILL_DOCUMENTATION ]
## 全局事件监听器去重
使用 `useSWRSubscription()` 在多个组件实例间共享全局事件监听器。
**错误做法(N 个实例 = N 个监听器):**
tsx
function useKeyboardShortcut(key: string, callback: () => void) {
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && e.key === key) {
callback()
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
}, [key, callback])
}
当多次使用 `useKeyboardShortcut` hook 时,每个实例都会注册一个新的监听器。
**正确做法(N 个实例 = 1 个监听器):**
tsx
import useSWRSubscription from 'swr/subscription'
// 模块级 Map 用于追踪每个按键的回调
const keyCallbacks = new Map<string, Set void>>()
function useKeyboardShortcut(key: string, callback: () => void) {
// 在 Map 中注册此回调
useEffect(() => {
if (!keyCallbacks.has(key)) {
keyCallbacks.set(key, new Set())
}
keyCallbacks.get(key)!.add(callback)
return () => {
const set = keyCallbacks.get(key)
if (set) {
set.delete(callback)
if (set.size === 0) {
keyCallbacks.delete(key)
}
}
}
}, [key, callback])
useSWRSubscription('global-keydown', () => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && keyCallbacks.has(e.key)) {
keyCallbacks.get(e.key)!.forEach(cb => cb())
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
})
}
function Profile() {
// 多个快捷键将共享同一个监听器
useKeyboardShortcut('p', () => { /* ... */ })
useKeyboardShortcut('k', () => { /* ... */ })
// ...
}