React 中的 onKeyDown / onKeyUp 侦听器
onKeyDown / onKeyUp listener in React
我正在尝试将事件侦听器添加到 React 中的图标,但它不起作用。我的代码:
const handleKey = (event) => {
console.log(event);
}
<MdOutlinePause onKeyDown={handleKey} />
我在同一个按钮上还有一个 onClick 处理程序,它运行良好,所以我真的很困惑为什么 onKeyDown 没有触发。感谢任何人可以提供的任何帮助!
在特定元素上使用 onKeyDown 需要焦点才能按预期工作。
我们可以通过添加 tabindex 属性使您的 MdOutlinePause
组件 focus-able。这将允许您通过点击选项卡或单击它来为图标提供焦点。该元素看起来像这样:
<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 的依赖项数组来解决这个问题,但这会导致我们的事件侦听器被删除并且每个渲染器上的 re-added 因为 handleKeyPress
将被更新在每个渲染器上。更好的解决方案是 将 callback 模式 与我们的 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 to useState, we can access the previous state as the first argument of the function. This allows for a much simpler approach, shown below and in this codesandbox.
const [text, setText] = useState("");
const handleKeyPress = event => {
setText(previousText => `${previousText}${event.key}`);
};
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);
我正在尝试将事件侦听器添加到 React 中的图标,但它不起作用。我的代码:
const handleKey = (event) => {
console.log(event);
}
<MdOutlinePause onKeyDown={handleKey} />
我在同一个按钮上还有一个 onClick 处理程序,它运行良好,所以我真的很困惑为什么 onKeyDown 没有触发。感谢任何人可以提供的任何帮助!
在特定元素上使用 onKeyDown 需要焦点才能按预期工作。
我们可以通过添加 tabindex 属性使您的 MdOutlinePause
组件 focus-able。这将允许您通过点击选项卡或单击它来为图标提供焦点。该元素看起来像这样:
<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 的依赖项数组来解决这个问题,但这会导致我们的事件侦听器被删除并且每个渲染器上的 re-added 因为 handleKeyPress
将被更新在每个渲染器上。更好的解决方案是 将 callback 模式 与我们的 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 to useState, we can access the previous state as the first argument of the function. This allows for a much simpler approach, shown below and in this codesandbox.
const [text, setText] = useState("");
const handleKeyPress = event => {
setText(previousText => `${previousText}${event.key}`);
};
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);