fix(web): stabilize useKeyboardShortcuts with ref-based callback

- Use useRef to hold shortcuts array, read from ref inside event handler
- Event listener registered once on mount (empty deps), avoids re-subscription
  when callers forget to memoize the shortcuts array
- Prevents subtle memory leak from rapid add/remove of keydown listeners
This commit is contained in:
saravanakumardb1 2026-03-10 19:54:50 -07:00
parent c2202e9e52
commit 420945e081

View File

@ -1,6 +1,6 @@
"use client";
import { useEffect } from "react";
import { useEffect, useRef } from "react";
export interface KeyboardShortcut {
key: string;
@ -12,6 +12,9 @@ export interface KeyboardShortcut {
}
export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]) {
const shortcutsRef = useRef(shortcuts);
shortcutsRef.current = shortcuts;
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
const target = event.target as HTMLElement;
@ -21,7 +24,7 @@ export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]) {
target.tagName === "SELECT" ||
target.isContentEditable;
for (const shortcut of shortcuts) {
for (const shortcut of shortcutsRef.current) {
const metaMatch = shortcut.meta ? event.metaKey || event.ctrlKey : !event.metaKey && !event.ctrlKey;
const shiftMatch = shortcut.shift ? event.shiftKey : !event.shiftKey;
const altMatch = shortcut.alt ? event.altKey : !event.altKey;
@ -39,5 +42,5 @@ export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]) {
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [shortcuts]);
}, []);
}