反应:onClick 与 OnKeyDown

React: onClick vs OnKeyDown

我对 React 编码还很陌生,但希望了解我继承的代码中的一些奇怪行为。以下代码片段在我试图了解的应用程序中驱动 pane/panel 关闭,但通过鼠标单击与 'Enter key'.

调用时的运行方式不同
const closeButton = (onClose) => (
  <div
    data-testid="abstract-pane-close-button"
    className="abstract-pane-component abstract-pane-close-button"
    onClick={onClose}
    aria-label="Close"
    type="button"
    role="button"
    tabIndex={0}
    onKeyDown={({ key }) => {
      if (key === keys.ENTER.key) {
        onClose();
      }
    }}
  >
    <CloseIcon />
  </div>
);

两者都调用 onClose 函数,后者又将一段状态数据设置为空对象。 pane/panel 的出现以该状态数据为非空为条件,因此调用 onClose 函数(并将状态数据设置为空)应该使其消失。这在通过 onClick 调用时工作正常,但不能通过 onKeyDown 调用。我很困惑!

一个显着的区别是通过 ENTER 键而不是通过点击事件调用时使用括号,但我很难理解这是否重要?任何人都可以提供见解......或者告诉我我进入了一个无关紧要的兔子洞吗?!

提前致谢

编辑:

keys 是导入的对象。其结构如下图:

export const keys = { 
  ENTER: { 
    key: 'Enter', 
    keyCode: 13 
  }, 
  ESCAPE: { 
    key: 'Escape', 
    keyCode: 27 
  }, 
  ESCAPE_IE_EDGE: { 
    key: 'Esc', 
    keyCode: 27 
  }, 
  ... ... 
}

试试这个

onKeyDown={(e) => {
 if (e.code === "Enter") {
   e.preventDefault();
   onClose();
 }
}}

您的问题是 onKeyDown 仅适用于焦点和交互元素。为了使其对您的情况有用,您应该在组件的 useEffect 内添加一个全局事件 keydown(记得也要清理全局事件)。

const keys = { 
  ENTER: { 
key: 'Enter', 
keyCode: 13 
  },
}
 
const CloseButton = ({onClose}) => {
  React.useEffect(() => {
     const handleKeyDown = ({ key }) => {
      if (key === keys.ENTER.key) {
        onClose();
      }
     }
     //add a global event for `keydown`
     window.addEventListener('keydown', handleKeyDown)
    //clean up after component unmounted
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [])

  return <div
    data-testid="abstract-pane-close-button"
    className="abstract-pane-component abstract-pane-close-button"
    onClick={onClose}
    aria-label="Close"
    type="button"
    role="button"
  >
    Button
  </div>
};

ReactDOM.render(
  <CloseButton onClose={() => alert('testing')}/>,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>