javascript - React 中的 onKeyDown/onKeyUp 监听器

标签 javascript reactjs keyboard-events

我正在尝试将事件监听器添加到 React 中的图标,但它不起作用。我的代码:

const handleKey = (event) => {
    console.log(event);
}

<MdOutlinePause onKeyDown={handleKey} />

我在同一个按钮上还有一个 onClick 处理程序,它运行良好,所以我真的很困惑为什么 onKeyDown 没有触发。感谢任何人可以提供的任何帮助!

最佳答案

在特定元素上使用 onKeyDown 需要焦点才能按预期工作。

我们可以通过添加 tabindex 使您的 MdOutlinePause 组件可聚焦属性。这将允许您通过点击选项卡或单击它来为图标提供焦点。该元素看起来像这样:

<MdOutlinePause tabIndex={0} onKeyDown={handleKey} />

如果您希望无需聚焦元素即可检测键事件,您需要附加一个事件监听器。我们可以用 useEffect 来做到这一点所以这发生在 Mount 上,我们会将事件监听器附加到 window,这样无论哪个元素具有焦点,它都能正常工作:

  /// Don't copy and paste this - see below
  useEffect(() => {
    window.addEventListener("keydown", handleKeyPress);
    });
  }, []);
  /// Don't copy and paste this - see below

这允许您检测键盘事件,这很好,但有一个问题:每当页面加载时 eventListener 会再次添加,但永远不会被删除。因此,您可能会遇到函数在每次按键时被多次调用的问题。

我们可以通过删除 return from useEffect 中的事件监听器来解决这个问题.这就是我们如何指定一个函数让 useEffect 清理 自身。这确保了我们的 useEffect 永远不会一次添加多个“keydown”事件监听器:

  useEffect(() => {
    window.addEventListener("keydown", handleKeyPress);

    return () => {
      window.removeEventListener("keydown", handleKeyPress);
    };
  }, []);

这是完整的 example on codesandbox

如果您不需要在 handleKeyPress 函数中访问状态,这会非常有用。


这是一个常见的用例,当用户执行某个操作时需要对状态变量做一些事情,如果我们需要访问更新后的状态,那么我们就会遇到一个问题:我们附加了 handleKeyPress到事件监听器 onMount 并且该函数永远不会更新,因此它将始终使用状态的初始版本。 This codesandbox说明了这个问题。

我们可以通过将 handleKeyPress 添加到 useEffect 的依赖项数组来解决这个问题,但这会导致我们的事件监听器被删除并在每次渲染时重新添加,因为 handleKeyPress 将在每个渲染器上更新。更好的解决方案是使用 callback pattern 与我们的 handleKeyPress 以便它只在实际需要时更新(当它依赖的状态被更新时)。我们还想将 handleKeyPress 添加到我们的 useEffect 依赖项数组中,以便在 handleKeyPress 函数更改时创建一个新的事件监听器:

  const handleKeyPress = useCallback((event) => {
    // do stuff with stateVariable and event
  }, [stateVariable]);

  useEffect(() => {
    window.addEventListener("keydown", handleKeyPress);

    return () => {
      window.removeEventListener("keydown", handleKeyPress);
    };
  }, [handleKeyPress]);

现在一切都适本地更新了! Here's a full example这个在 codesandbox 上。


还有一种解决方案可以让您以最简单的方式访问状态。缺点是您唯一可以访问的状态变量(具有更新的值)将是您正在更新的状态变量,因此此解决方案是视情况而定的。要访问其他状态变量,您必须使用上述解决方案。

通过 passing a function对于 useState,我们可以访问前一个状态作为函数的第一个参数。这允许采用更简单的方法,如下所示和 this codesandbox 中所示。 .

  const [text, setText] = useState("");

  const handleKeyPress = event => {
    setText(previousText => `${previousText}${event.key}`);
  };

  useEffect(() => {
    window.addEventListener("keydown", handleKeyPress);

    return () => {
      window.removeEventListener("keydown", handleKeyPress);
    };
  }, []);

关于javascript - React 中的 onKeyDown/onKeyUp 监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71822354/

相关文章:

javascript - 在不改变状态的情况下 react 过滤器方法

reactjs - 使用 js 源映射中的 React 组件

java - 无法将 Control-Backspace 映射到 KeyStroke

快速移动文本字段问题

Haskell:如何捕获键盘按下,如上、下、左、右

javascript - 如何在.load()之后获取javascript函数的返回值?

javascript - 即使使用 `Cache-Control: max-age`,浏览器是否继续发送资源请求

javascript - Internet Explorer中的pcm数据支持

javascript - 如何使用 javascript 检测触摸设备浏览器与桌面?

javascript - react 对象表达?