Skip to content

Commit

Permalink
Added more options
Browse files Browse the repository at this point in the history
Swapped deps and options param.
Updated docz.
  • Loading branch information
JohannesKlauss committed Apr 4, 2020
1 parent 66914ef commit 5881da1
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 54 deletions.
68 changes: 18 additions & 50 deletions docs/useHotkeys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ import { useHotkeys } from '../src';

The `useHotkeys` hook follows the hotkeys call signature.

The callback function takes the exact parameters as the callback function in the hotkeys package.
See hotkeys documentation for more info or look into the typings file.

When the component gets mounted into the DOM, it will listen for the keystroke. When the component will unmount, it
stops listening for the keystroke.

```ts
useHotkeys(keys: string, callback: (event: KeyboardEvent, handler: HotkeysEvent) => void, deps: any[] = [])
useHotkeys(keys: string, callback: (event: KeyboardEvent, handler: HotkeysEvent) => void, options: Options = {}, deps: any[] = [])
```

## Parameters
Expand All @@ -27,13 +24,16 @@ section on the hotkeys documentation for more info.
* `callback: (event: KeyboardEvent, handler: HotkeysEvent) => void`: Gets executed when the defined keystroke
gets hit by the user. **Important:** Since version 1.5.0 this callback gets memoised inside the hook. So you don't have
to do this anymore by yourself.
* `options: Options = {}` Pass options directly to the hotkeys package. See [Options](#options) section for more details.
* `deps: any[] = []`: The dependency array that gets appended to the memoisation of the callback. Here you define the inner
dependencies of your callback. If for example your callback actions depend on a referentially unstable value or a value
that will change over time, you should add this value to your deps array. Since most of the time your callback won't
depend on any unstable callbacks or changing values over time you can leave this value alone since it will be set to an
empty array by default. See the [Memoisation](#memoisation) section to
learn more and see an example where you have to set this array.

**Breaking Change in 2.0**: Since version 2.0 the `options` and `deps` parameter switched positions.

## Example

This will listen to the `ctrl+k` keystroke. If you press it, the counter increments by one. If `ctrl+l` gets pressed,
Expand All @@ -43,27 +43,12 @@ the counter will decrement by one.
Due to the nature of how `useEffect` works and to prevent resetting the hotkeys handler during every render, before 1.5.0
you had to memoise your callback yourself. Since this is tedious work and dependency arrays are a common pattern with
React hooks, I decided to bring the memoisation inside the hook, so you don't have to deal with it. Please read the
**Memoisation** section for more info on this.
[**Memoisation**](#memoisation) section for more info on this.

```js
import { useHotkeys } from 'react-hotkeys-hook';
```

```jsx
const AddToBankComponent = () => {
const [amount, setAmount] = useState(0);

useHotkeys('ctrl+a', () => setAmount(prevAmount => prevAmount + 100));
useHotkeys('ctrl+d', () => setAmount(prevAmount => prevAmount - 100));

return (
<div>
{amount >= 0 ? 'Add' : 'Remove'} {Math.abs(amount)} dollars {amount >= 0 ? 'from' : 'to'} my bank account.
</div>
);
};
```

<Playground>
{() => {
const [amount, setAmount] = useState(0);
Expand All @@ -77,24 +62,21 @@ const AddToBankComponent = () => {
}}
</Playground>

## Memoisation
## Options

Let's check out a slightly different example to see how memoisation effects your application.
The options parameter is used to pass options directly to the hotkeys package. Check out the [hotkeys docs](https://github.com/jaywcjlove/hotkeys/#option)
for an overview.

```jsx
const AddToBankComponent = () => {
const [amount, setAmount] = useState(0);
### Parameters
* `filter: (event: KeyboardEvent): boolean` is used to enable hotkeys inside input elements. Check out [hotkeys docs](https://github.com/jaywcjlove/hotkeys/#filter) for usage
* `splitKey: string` is used to change the splitting character inside the keys argument. Default is `+`, but if you want
to listen to the `+` character, you can set `splitKey` to i.e. `-` and listen for `ctrl-+`
* `keyup: boolean` Determine if you want to listen on the keyup event
* `keydown: boolean` Determine if want to listen on the keydown event

// Don't use this in production, won't work as expected.
useHotkeys('n', () => setAmount(amount + 100), []);
## Memoisation

return (
<div>
Add {Math.abs(amount)} dollars to my bank account.
</div>
);
};
```
Let's check out a slightly different example to see how memoisation effects your application.

<Playground>
{() => {
Expand All @@ -120,24 +102,10 @@ So our logic flow got stuck, tis not what we wanted.
To fix this there are two approaches when using values that are retrieved by `useState`. You could define a dependency array as
the third parameter like so:

```jsx
const AddToBankComponent = () => {
const [amount, setAmount] = useState(0);

// Works, but has performance and binding issues.
useHotkeys('m', () => setAmount(amount + 100), [amount]);

return (
<div>
Add {Math.abs(amount)} dollars to my bank account.
</div>
);
};
```

<Playground>
{() => {
const [amount, setAmount] = useState(0);
// Works but has binding issues
useHotkeys('m', () => setAmount(amount + 100), [amount]);
return (
<div>
Expand Down Expand Up @@ -165,4 +133,4 @@ const AddToBankComponent = () => {
</div>
);
};
```
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"@types/react-dom": "16.9.6",
"docz": "2.3.0",
"emotion-theming": "10.0.27",
"gatsby-plugin-emotion": "4.2.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"typescript": "3.8.3"
Expand Down
12 changes: 8 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import hotkeys, { KeyHandler } from "hotkeys-js";
import { useCallback, useEffect } from "react";
import hotkeys, {KeyHandler} from "hotkeys-js";
import {useCallback, useEffect} from "react";

type Options = {
filter?: typeof hotkeys.filter;
splitKey?: string;
scope?: string;
keyUp?: boolean;
keyDown?: boolean;
};

export function useHotkeys(
keys: string,
callback: KeyHandler,
options: Options = {},
deps: any[] = [],
options: Options = {}
) {
const memoisedCallback = useCallback(callback, deps);

useEffect(() => {
if (options.filter) hotkeys.filter = options.filter;

hotkeys(keys, memoisedCallback);
hotkeys(keys, options, memoisedCallback);

return () => hotkeys.unbind(keys, memoisedCallback);
}, [memoisedCallback, options]);
Expand Down
32 changes: 32 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2359,6 +2359,13 @@
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.8.7":
version "7.9.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/standalone@^7.4.5":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.7.4.tgz#9adcda4b7c33627c65eacf87f5c1f950987294c2"
Expand Down Expand Up @@ -2551,6 +2558,13 @@
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"

"@emotion/babel-plugin-jsx-pragmatic@^0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin-jsx-pragmatic/-/babel-plugin-jsx-pragmatic-0.1.5.tgz#27debfe9c27c4d83574d509787ae553bf8a34d7e"
integrity sha512-y+3AJ0SItMDaAgGPVkQBC/S/BaqaPACkQ6MyCI2CUlrjTxKttTVfD3TMtcs7vLEcLxqzZ1xiG0vzwCXjhopawQ==
dependencies:
"@babel/plugin-syntax-jsx" "^7.2.0"

"@emotion/babel-preset-css-prop@^10.0.23":
version "10.0.23"
resolved "https://registry.yarnpkg.com/@emotion/babel-preset-css-prop/-/babel-preset-css-prop-10.0.23.tgz#7c21a36c97c3ce9e96f5896b56f68b9bbac800bd"
Expand All @@ -2561,6 +2575,16 @@
"@emotion/babel-plugin-jsx-pragmatic" "^0.1.4"
babel-plugin-emotion "^10.0.23"

"@emotion/babel-preset-css-prop@^10.0.27":
version "10.0.27"
resolved "https://registry.yarnpkg.com/@emotion/babel-preset-css-prop/-/babel-preset-css-prop-10.0.27.tgz#58868d9a6afee0eeaeb0fa9dc5ccb1b12d4f786b"
integrity sha512-rducrjTpLGDholp0l2l4pXqpzAqYYGMg/x4IteO0db2smf6zegn6RRZdDnbaoMSs63tfPWgo2WukT1/F1gX/AA==
dependencies:
"@babel/plugin-transform-react-jsx" "^7.3.0"
"@babel/runtime" "^7.5.5"
"@emotion/babel-plugin-jsx-pragmatic" "^0.1.5"
babel-plugin-emotion "^10.0.27"

"@emotion/cache@^10.0.17":
version "10.0.17"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.17.tgz#3491a035f62f276620d586677bfc3d4fad0b8472"
Expand Down Expand Up @@ -7487,6 +7511,14 @@ gatsby-plugin-compile-es6-packages@^2.0.0:
"@babel/runtime" "^7.0.0"
regex-escape "^3.4.8"

[email protected]:
version "4.2.1"
resolved "https://registry.yarnpkg.com/gatsby-plugin-emotion/-/gatsby-plugin-emotion-4.2.1.tgz#d4244460e23d1bb5cca76266ba8990f534234e32"
integrity sha512-ygXxkpnWJdDOAgb1XA9TbVCRLkaAYTFLTsqVQXMBhnrknb5iPNO+MP0fZ5LRqWgBALyJ629nxs0efUpnT/RSWw==
dependencies:
"@babel/runtime" "^7.8.7"
"@emotion/babel-preset-css-prop" "^10.0.27"

gatsby-plugin-emotion@^4.1.2:
version "4.1.16"
resolved "https://registry.yarnpkg.com/gatsby-plugin-emotion/-/gatsby-plugin-emotion-4.1.16.tgz#7ac7f03f8b2a1c93ff0ecd2378a14c97ef9380b1"
Expand Down

0 comments on commit 5881da1

Please sign in to comment.