react-hotkeys icon indicating copy to clipboard operation
react-hotkeys copied to clipboard

keybindings break on re-render

Open KutnerUri opened this issue 4 years ago • 11 comments

I am really excited about this new version - using integrated react events should solve a lot of head aches and workarounds I'm having right now.

I am trying the new version, and I don't always get key triggers. I think this is because my component re-renders when I click on it.

It definitely gets worse when I set onFocus={}

Expected behavior Hot keys matches should always trigger action, when hot key element is focused.

Platform (please complete the following information):

  • version: 2.0.0
  • chrome
  • OS: MacOS Mojave

Code to reproduce:

import React, { useState } from "react";
import { HotKeys,configure } from "react-hotkeys";

export function App() {
  const [state, setState] = useState(1);

  return (
    <div className="App">
      <div>{state}</div>
      <SubApp state={state} setState={setState} />
    </div>
  );
};

function SubApp({ state, setState }) {
  const go = e => {
    console.log("GO", state, 'key:', e.key);
    setState(state + 1);
  };

  return (
    <HotKeys
      keyMap={{ GO: "enter" }}
      handlers={{ GO: go }}
      allowChanges={true}
      //makes things worse:
      // onFocus={() => console.log("onFocus")}
    >
      hello! {state}
    </HotKeys>
  );
}

KutnerUri avatar Jul 17 '19 13:07 KutnerUri

adding log:

HotKeys (F0📕-E0❤️-C0🔺) Registered component:
 {
    "childIds": [],
    "parentId": null,
    "keyMap": {
        "GO": "enter"
    }
}
AbstractKeyEventStrategy.js:351 HotKeys (F0📕-E0❤️-C0🔺) Registered component mount:
 {
    "childIds": [],
    "parentId": null,
    "keyMap": {
        "GO": "enter"
    }
}
FocusOnlyKeyEventStrategy.js:246 HotKeys (F0📕-C0🔺-P0🔺:) Focused. 

FocusOnlyKeyEventStrategy.js:249 HotKeys (F0📕-C0🔺-P0🔺:) Component options:
 {
    "actions": {
        "GO": [
            {
                "prefix": "",
                "actionName": "GO",
                "sequenceLength": 1,
                "id": "Enter",
                "keyDictionary": {
                    "Enter": true
                },
                "keyEventType": 0,
                "size": 1
            }
        ]
    },
    "handlers": {
        "GO": "e => {\n    console.log(\"GO\", state, 'key:', e.key);\n    setState(state + 1);\n  }"
    },
    "componentId": 0,
    "options": {
        "defaultKeyEvent": "keydown"
    }
}
FocusOnlyKeyEventStrategy.js:391 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) New 'Enter' keydown event.
FocusOnlyKeyEventStrategy.js:626 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Added 'Enter' to current combination: 'Enter'.
FocusOnlyKeyEventStrategy.js:631 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Key history: [
    {
        "keys": {
            "Enter": [
                [
                    0,
                    0,
                    0
                ],
                [
                    1,
                    0,
                    0
                ]
            ]
        },
        "ids": [
            "Enter"
        ],
        "keyAliases": {}
    }
].
FocusOnlyKeyEventStrategy.js:741 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Attempting to find action matching 'Enter' keydown . . .
AbstractKeyEventStrategy.js:451 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Internal key mapping:
 {
    "": {
        "actionConfigs": {
            "Enter": {
                "prefix": "",
                "sequenceLength": 1,
                "id": "Enter",
                "keyDictionary": {
                    "Enter": true
                },
                "size": 1,
                "events": {
                    "0": {
                        "actionName": "GO",
                        "handler": "e => {\n    console.log(\"GO\", state, 'key:', e.key);\n    setState(state + 1);\n  }"
                    }
                }
            }
        },
        "order": null
    }
}
AbstractKeyEventStrategy.js:464 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Found action that matches 'Enter': GO. Calling handler . . .
App.js:23 GO 1 key: Enter
FocusOnlyKeyEventStrategy.js:601 HotKeys (F0📕-E1💚-C0🔺-P0🔺:) Stopping further event propagation.
FocusOnlyKeyEventStrategy.js:391 HotKeys (F0📕-E3💛-C0🔺-P0🔺:) New (simulated) 'Enter' keypress event.
FocusOnlyKeyEventStrategy.js:631 HotKeys (F0📕-E3💛-C0🔺-P0🔺:) Key history: [
    {
        "keys": {
            "Enter": [
                [
                    1,
                    0,
                    0
                ],
                [
                    1,
                    2,
                    0
                ]
            ]
        },
        "ids": [
            "Enter"
        ],
        "keyAliases": {}
    }
].
FocusOnlyKeyEventStrategy.js:730 HotKeys (F0📕-E3💛-C0🔺-P0🔺:) Ignored 'Enter' keypress because it doesn't have any keypress handlers.
FocusOnlyKeyEventStrategy.js:281 HotKeys (F0📕-C0🔺-P0🔺:) Received new props.
FocusOnlyKeyEventStrategy.js:291 HotKeys (F0📕-C0🔺-P0🔺:) Component options:
 {
    "actions": {
        "GO": [
            {
                "prefix": "",
                "actionName": "GO",
                "sequenceLength": 1,
                "id": "Enter",
                "keyDictionary": {
                    "Enter": true
                },
                "keyEventType": 0,
                "size": 1
            }
        ]
    },
    "handlers": {
        "GO": "e => {\n    console.log(\"GO\", state, 'key:', e.key);\n    setState(state + 1);\n  }"
    },
    "componentId": 0,
    "options": {
        "defaultKeyEvent": "keydown"
    }
}
FocusOnlyKeyEventStrategy.js:432 HotKeys (F0📕-E3💛-C0🔺-P0🔺:) Ignored 'Enter' keypress as it was not expected, and has already been simulated.
EventPropagator.js:268 HotKeys (F0📕-E3💛-Cnull🔺) Stopping further event propagation.
FocusOnlyKeyEventStrategy.js:313 HotKeys (F0📕-C0🔺-P0🔺:) Lost focus.
KeyEventManager.js:183 HotKeys: Window focused - clearing key history
FocusOnlyKeyEventStrategy.js:246 HotKeys (F1📗-C0🔺-P0🔺:) Focused. 

FocusOnlyKeyEventStrategy.js:249 HotKeys (F1📗-C0🔺-P0🔺:) Component options:
 {
    "actions": {
        "GO": [
            {
                "prefix": "",
                "actionName": "GO",
                "sequenceLength": 1,
                "id": "Enter",
                "keyDictionary": {
                    "Enter": true
                },
                "keyEventType": 0,
                "size": 1
            }
        ]
    },
    "handlers": {
        "GO": "e => {\n    console.log(\"GO\", state, 'key:', e.key);\n    setState(state + 1);\n  }"
    },
    "componentId": 0,
    "options": {
        "defaultKeyEvent": "keydown"
    }
}

KutnerUri avatar Jul 17 '19 13:07 KutnerUri

Hey @KutnerUri, it's fantastic to hear you're excited about the improvements v2 brings.

Thank you for including your logs, that is generally the most helpful thing people can do short of creating a demo of the problem.

Were these logs for an instance where an action trigger was missed? There appears to be nothing awry in them - the Enter key seems to have been pressed once. The window is unfocused half way through the log - are you sure subsequent presses of the Enter key aren't occurring when the window is out of focus?

greena13 avatar Jul 19 '19 07:07 greena13

Yes, I am sure. try it for yourself: https://codesandbox.io/embed/compassionate-maxwell-hxs8y

KutnerUri avatar Jul 26 '19 08:07 KutnerUri

Running into this issue on an app I'm working on as well. What's really weird is this sequence:

  1. Trigger hotkey, causing rerender
  2. Hotkeys are broken
  3. Focus other application
  4. Refocus browser (without interacting with react application)
  5. Hotkeys work

negasora avatar Aug 05 '19 15:08 negasora

Is there a fix to this? I'm experiencing the same problem.

The hotkeys work on mount but after the first render they break. I console logged it and it seems like the keyMap and handler props are resetting. I'm not sure if that's the the problem.

johnli611 avatar Aug 13 '19 12:08 johnli611

Has anyone found a workaround for this?

negasora avatar Aug 27 '19 21:08 negasora

Running into this issue on an app I'm working on as well. What's really weird is this sequence:

  1. Trigger hotkey, causing rerender
  2. Hotkeys are broken
  3. Focus other application
  4. Refocus browser (without interacting with react application)
  5. Hotkeys work

I'm observing something very similar to what you are describing.

  1. click on input inside <HotKeys?
  2. input some value, e.g. "a"
  3. press "enter"

Expect: The "enter" handler to trigger. Actual: The "enter" handler does not trigger.

Interestingly, if i skip step 2. i the "enter" handler does trigger.

henrikq avatar Oct 02 '19 16:10 henrikq

My example is rather complicated. I have multiple GlobalHotKeys instances (that work as expected) in play in addition the HotKeys component that is giving me trouble.

I attempted to reproduce in a simpler example. I was not able to reproduce the behavior that I am seeing, but i did reproduce some behavior that i would think is a bug, and it may be connected.

https://codesandbox.io/s/react-hotkeys-r8xp8

henrikq avatar Oct 02 '19 16:10 henrikq

Yes, I am sure. try it for yourself: https://codesandbox.io/embed/compassionate-maxwell-hxs8y

adding configure({ simulateMissingKeyPressEvents: false }); works around this issue . Same for https://codesandbox.io/s/react-hotkeys-r8xp8. This does cause problems though on my project when handling 2+ key sequences (eg IMAGE_ZOOM_OUT: 'alt+-') only working once you repress the held down key.

lukehowkins avatar Oct 08 '19 16:10 lukehowkins

I was able to fix @KutnerUri's issue by bluring and refocusing document.activeElement. Obviously a very hacky solution but could be a clue as to how to fix the underlying issue.

https://codesandbox.io/s/xenodochial-cherry-ikcr2?file=/src/index.js

seveibar avatar May 24 '20 09:05 seveibar

I can reproduce this even if the app never re-renders. The handling stops working after pressing the enter key. It does not have to be defined in the keymap either. Although, it continues working when I call preventDefault with an extra even handler on the enter key.

Edit: Seems fixed in the forked react-hotkeys-ce package.

radoslavkarlik avatar Mar 17 '21 07:03 radoslavkarlik