---
title: Sneltoetsen
image: /images/user-guide/table-views/table.png
---

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

## Inleiding

Wanneer je naar een sneltoets moet luisteren, zou je normaal gesproken de `onKeyDown`-eventlistener gebruiken.

In `twenty-front` kun je echter conflicten hebben tussen dezelfde sneltoetsen die in verschillende onderdelen worden gebruikt, die op hetzelfde moment geladen zijn.

Als je bijvoorbeeld een pagina hebt die naar de Enter-toets luistert en een modaal die naar de Enter-toets luistert, met een Select-component binnen die modaal die naar de Enter-toets luistert, dan kun je een conflict hebben wanneer ze allemaal tegelijkertijd geladen zijn.

## De `useScopedHotkeys` hook

Om dit probleem op te lossen hebben we een aangepaste hook die het mogelijk maakt om zonder conflicten naar sneltoetsen te luisteren.

Je plaatst deze in een onderdeel, en deze zal alleen naar de sneltoetsen luisteren wanneer het onderdeel geladen is EN wanneer de gespecificeerde **sneltoetsscope** actief is.

## Hoe luister je praktisch naar sneltoetsen?

Er zijn twee stappen om het luisteren naar sneltoetsen op te zetten:

1. Stel de [sneltoetsscope](#what-is-a-hotkey-scope-) in die naar sneltoetsen luistert.
2. Gebruik de `useScopedHotkeys` hook om naar sneltoetsen te luisteren.

Het instellen van sneltoetsscopes is nodig, zelfs op gewone pagina's, omdat andere UI-elementen zoals het linkermenu of het commandmenu ook naar sneltoetsen kunnen luisteren.

## Toepassingen van sneltoetsen

Over het algemeen heb je twee toepassingen waarvoor sneltoetsen nodig zijn:

1. Op een pagina of een component geladen op een pagina.
2. In een modaal type component dat de focus krijgt door een gebruikersactie.

De tweede toepassing kan herhaaldelijk voorkomen: bijvoorbeeld een dropdown in een modaal.

### Luisteren naar sneltoetsen op een pagina

Voorbeeld:

```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>;
};
```

### Luisteren naar sneltoetsen in een modaaltype component

In dit voorbeeld zullen we een modaal component gebruiken dat naar de Escape-toets luistert om zijn ouder te vertellen het te sluiten.

Hier verandert de gebruikersinteractie de scope.

```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>;
};
```

Dan in het modaal component:

```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>;
};
```

Het is belangrijk om dit patroon te gebruiken wanneer je er niet zeker van bent dat alleen een useEffect met laden/niet-laden voldoende zal zijn om conflicten te vermijden.

Die conflicten kunnen moeilijk te debuggen zijn en kunnen vaker voorkomen dan niet met useEffects.

## Wat is een sneltoetsscope?

Een sneltoetsscope is een string die een context vertegenwoordigt waarin de sneltoetsen actief zijn. Het wordt over het algemeen gecodeerd als een enum.

Wanneer je de sneltoetsscope verandert, worden de sneltoetsen die naar deze scope luisteren ingeschakeld en worden de sneltoetsen die naar andere scopes luisteren uitgeschakeld.

Je kunt maar één scope tegelijk instellen.

Als voorbeeld worden de sneltoetsscopes voor elke pagina gedefinieerd in de `PageHotkeyScope` enum:

```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',
}
```

Intern wordt de momenteel geselecteerde scope opgeslagen in een Recoil-toestand die over de hele applicatie gedeeld wordt:

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

Maar deze Recoil-toestand mag nooit handmatig worden behandeld! We zullen zien hoe we het in de volgende sectie kunnen gebruiken.

## Hoe werkt het intern?

We hebben een dunne wrapper gemaakt bovenop [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) die het efficiënter maakt en onnodige her-renders vermijdt.

We creëren ook een Recoil-toestand om de sneltoetsscope te beheren en deze overal in de applicatie beschikbaar te maken.