---
title: קיצורי מקשים
image: /images/user-guide/table-views/table.png
---

<Frame>
  <img src="/images/user-guide/table-views/table.png" alt="Header" />
</Frame>

## הקדמה

כאשר אתה צריך להאזין לקיצור מקשים, בדרך כלל תשתמש במאזין לאירועים `onKeyDown`.

ב-`twenty-front` עם זאת, יתכנו קונפליקטים בין אותם קיצורי מקשים בשימוש ברכיבים שונים שמותקנים באותו הזמן.

למשל, אם יש לך דף שמאזין למקש Enter, ומודאל שמאזין למקש Enter עם רכיב Select בתוך המודאל שמאזין גם כן למקש Enter, יתכן שתהיה לך התנגשות כאשר כולם מותקנים באותו הזמן.

## הוק `useScopedHotkeys`

כדי להתמודד עם הבעיה הזו, יש לנו הוק מותאם אישית שמאפשר להאזין לקיצורי מקשים ללא קונפליקטים.

אתה מציב אותו ברכיב, והוא יאזין לקיצורי המקשים רק כאשר הרכיב מוטמע וכאשר **תחום קיצור המקשים** הנקוב פעיל.

## איך להאזין לקיצורי מקשים בפועל?

There are two steps involved in setting up hotkey listening :

1. הגדר את [תחום קיצור המקשים](#what-is-a-hotkey-scope-) שיאזין לקיצורי מקשים
2. השתמש בהוק `useScopedHotkeys` להאזנה לקיצורי מקשים

הגדרת תחומי קיצורי מקשים היא חובה גם בדפים פשוטים, כי רכיבי UI אחרים כמו תפריט שמאל או תפריט פקודות עשויים גם כן להאזין לקיצורי מקשים.

## מקרי שימוש לקיצורי מקשים

בכלליות, יהיו לך שני מקרי שימוש הדורשים קיצורי מקשים:

1. בדף או רכיב מותקן בדף
2. ברכיב מסוג מודאל שתופס את המוקד בעקבות פעולת משתמש

מקרה השימוש השני יכול לקרות בצורה רקרוסיבית: למשל תפריט נפתח במודאל.

### האזנה לקיצורי מקשים בדף

דוגמא :

```tsx
const PageListeningEnter = () => {
  const {
    setHotkeyScopeAndMemorizePreviousScope,
    goBackToPreviousHotkeyScope,
  } = usePreviousHotkeyScope();

  // 1. Set the hotkey scope in a useEffect
  useEffect(() => {
    setHotkeyScopeAndMemorizePreviousScope(
      ExampleHotkeyScopes.ExampleEnterPage,
    );

    // Revert to the previous hotkey scope when the component is unmounted
    return () => {
      goBackToPreviousHotkeyScope();
    };
  }, [goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope]);

  // 2. Use the useScopedHotkeys hook
  useScopedHotkeys(
    Key.Enter,
    () => {
      // Some logic executed on this page when the user presses Enter
      // ...
    },
    ExampleHotkeyScopes.ExampleEnterPage,
  );

  return <div>My page that listens for Enter</div>;
};
```

### האזנה לקיצורי מקשים ברכיב מסוג מודאל

בדוגמה זו נשתמש ברכיב מודאל שמאזין למקש Escape כדי להגיד להורה שלו לסגור אותו.

כאן פעולת המשתמש משנה את התחום.

```tsx
const ExamplePageWithModal = () => {
  const [showModal, setShowModal] = useState(false);

  const {
    setHotkeyScopeAndMemorizePreviousScope,
    goBackToPreviousHotkeyScope,
  } = usePreviousHotkeyScope();

  const handleOpenModalClick = () => {
    // 1. Set the hotkey scope when user opens the modal
    setShowModal(true);
    setHotkeyScopeAndMemorizePreviousScope(
      ExampleHotkeyScopes.ExampleModal,
    );
  };

  const handleModalClose = () => {
    // 1. Revert to the previous hotkey scope when the modal is closed
    setShowModal(false);
    goBackToPreviousHotkeyScope();
  };

  return <div>
    <h1>My page with a modal</h1>
    <button onClick={handleOpenModalClick}>Open modal</button>
    {showModal && <MyModalComponent onClose={handleModalClose} />}
  </div>;
};
```

ואז ברכיב המודאל:

```tsx
const MyDropdownComponent = ({ onClose }: { onClose: () => void }) => {
  // 2. Use the useScopedHotkeys hook to listen for Escape.
  // Note that escape is a common hotkey that could be used by many other components
  // So it's important to use a hotkey scope to avoid conflicts
  useScopedHotkeys(
    Key.Escape,
    () => {
      onClose()
    },
    ExampleHotkeyScopes.ExampleModal,
  );

  return <div>My modal component</div>;
};
```

חשוב להשתמש בדפוס הזה כשאתה לא בטוח שסתם שימוש ב-useEffect עם הטענת/פירוק מספיק כדי להימנע מקונפליקטים.

הקונפליקטים האלה יכולים להיות קשים לאיתור, ועלול לקרות לעתים קרובות עם useEffects.

## מהו תחום קיצור מקשים?

תחום קיצור מקשים הוא מחרוזת שמייצגת הקשר שבו קיצורי המקשים פעילים. בדרך כלל, זה מקודד כ-enum.

כאשר אתה משנה את התחום של קיצור המקשים, הקיצורים שמאזינים לתחום זה יופעלו, והקיצורים שמאזינים לתחומים אחרים יושבתו.

באפשרותך להגדיר רק תחום אחד בכל פעם.

לדוגמה, תחומי קיצורי המקשים לכל דף מוגדרים ב-enum `PageHotkeyScope`:

```tsx
export enum PageHotkeyScope {
  Settings = 'settings',
  CreateWorkspace = 'create-workspace',
  SignInUp = 'sign-in-up',
  CreateProfile = 'create-profile',
  PlanRequired = 'plan-required',
  ShowPage = 'show-page',
  PersonShowPage = 'person-show-page',
  CompanyShowPage = 'company-show-page',
  CompaniesPage = 'companies-page',
  PeoplePage = 'people-page',
  OpportunitiesPage = 'opportunities-page',
  ProfilePage = 'profile-page',
  WorkspaceMemberPage = 'workspace-member-page',
  TaskPage = 'task-page',
}
```

באופן פנימי, התחום הנבחר כרגע מאוחסן במצב Recoil שמשותף בכל האפליקציה:

```tsx
export const currentHotkeyScopeState = createState<HotkeyScope>({
  key: 'currentHotkeyScopeState',
  defaultValue: INITIAL_HOTKEYS_SCOPE,
});
```

אך יש להימנע מהתעסקות ידנית במצב Recoil זה! נלמד איך להשתמש בו בחלק הבא.

## איך זה עובד פנימית?

יצרנו עוטף דק על גבי [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) שהופך אותו ליותר ביצועי ומונע רינדורים מיותרים.

כמו כן, אנו יוצרים מצב Recoil לטפל במצב תחום קיצור המקשים ולהפוך אותו לזמין בכל האפליקציה.