[reactjs] reactjs에서 문서 키 누르기 듣기

escape눌러서 활성 반응 부트 스트랩 팝 오버를 닫기 위해 바인딩하고 싶습니다 . 여기에 코드가 있습니다.

_handleEscKey:function(event){
         console.log(event);
        if(event.keyCode == 27){
          this.state.activePopover.hide();
        }
   },

  componentWillMount:function(){
     BannerDataStore.addChangeListener(this._onchange);
     document.addEventListener("click", this._handleDocumentClick, false);
     document.addEventListener("keyPress", this._handleEscKey, false);
   },


   componentWillUnmount: function() {
     BannerDataStore.removeChangeListener(this._onchange);
      document.removeEventListener("click", this._handleDocumentClick, false);
      document.removeEventListener("keyPress", this._handleEscKey, false);
   },

하지만 아무 키나 눌러도 콘솔에 아무것도 기록되지 않습니다. 나는 창에서도 다른 경우를 들으려고 노력했지만 .’keypress ‘,’keyup ‘등을했지만 내가 뭔가 잘못하고있는 것 같습니다.



답변

당신은 사용해야 keydown하지 keypress.

키 누르기 (더 이상 사용되지 않음)는 일반적으로 문서에 따라 문자 출력을 생성하는 키에만 사용됩니다.

키 누르기 (사용되지 않음)

키 누르기 이벤트는 키를 눌렀을 때 발생하며 해당 키는 일반적으로 문자 값을 생성합니다.

키 다운

keydown 이벤트는 키를 눌렀을 때 시작됩니다.


답변

이것과 비슷한 문제가 있습니다. 수정 사항을 설명하기 위해 코드를 사용하겠습니다.

// for other devs who might not know keyCodes
var ESCAPE_KEY = 27;

_handleKeyDown = (event) => {
    switch( event.keyCode ) {
        case ESCAPE_KEY:
            this.state.activePopover.hide();
            break;
        default:
            break;
    }
},

// componentWillMount deprecated in React 16.3
componentDidMount(){
    BannerDataStore.addChangeListener(this._onchange);
    document.addEventListener("click", this._handleDocumentClick, false);
    document.addEventListener("keydown", this._handleKeyDown);
},


componentWillUnmount() {
    BannerDataStore.removeChangeListener(this._onchange);
    document.removeEventListener("click", this._handleDocumentClick, false);
    document.removeEventListener("keydown", this._handleKeyDown);
},

작업을 수행하는 createClass 방식을 사용하고 있으므로 this정의 된 각 메소드에 내재 된 것처럼 특정 메소드에 바인딩 할 필요가 없습니다 .

여기 React 컴포넌트 생성의 createClass 메소드를 사용하는 jsfiddle이 작동 합니다.


답변

React Hooks를 사용할 수 있다면 좋은 방법은에 대한 useEffect것이므로 이벤트 리스너는 한 번만 구독되고 구성 요소가 마운트 해제 될 때 제대로 구독 해제됩니다.

아래 예제는 https://usehooks.com/useEventListener/ 에서 추출되었습니다 .

// Hook
function useEventListener(eventName, handler, element = window){
  // Create a ref that stores handler
  const savedHandler = useRef();

  // Update ref.current value if handler changes.
  // This allows our effect below to always get latest handler ...
  // ... without us needing to pass it in effect deps array ...
  // ... and potentially cause effect to re-run every render.
  useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(
    () => {
      // Make sure element supports addEventListener
      // On 
      const isSupported = element && element.addEventListener;
      if (!isSupported) return;

      // Create event listener that calls handler function stored in ref
      const eventListener = event => savedHandler.current(event);

      // Add event listener
      element.addEventListener(eventName, eventListener);

      // Remove event listener on cleanup
      return () => {
        element.removeEventListener(eventName, eventListener);
      };
    },
    [eventName, element] // Re-run if eventName or element changes
  );
};

또한, 예를 들면, NPM에서 설치할 수 있습니다 npm i @use-it/event-listener– – 여기에 프로젝트 참조 https://github.com/donavon/use-event-listener을 .

그런 다음 구성 요소에서 사용하려면 이벤트 이름과 핸들러를 전달하는 기능 구성 요소 내에서 호출하면됩니다. 예를 들어 console.logEscape 키를 누를 때마다 원하는 경우 :

import useEventListener from '@use-it/event-listener'

const ESCAPE_KEYS = ['27', 'Escape'];

const App = () => {
  function handler({ key }) {
    if (ESCAPE_KEYS.includes(String(key))) {
      console.log('Escape key pressed!');
    }
  }

  useEventListener('keydown', handler);

  return <span>hello world</span>;
}


답변

이 질문과 더 관련이있는 Jt oso의 답변 버전입니다. 외부 라이브러리 또는 API 후크를 사용하여 리스너를 바인딩 / 바인딩 해제하는 다른 답변보다 훨씬 간단하다고 생각합니다.

var KEY_ESCAPE = 27;
...
    function handleKeyDown(event) {
        if (event.keyCode === KEY_ESCAPE) {
            /* do your action here */
        }
    }
...
    <div onKeyDown={handleKeyDown}>
...


답변

탭 가능한 div에 대해 동일한 요구 사항이있었습니다.

나를 위해 다음 코드는 items.map ((item) => …

  <div
    tabindex="0"
    onClick={()=> update(item.id)}
    onKeyDown={()=> update(item.id)}
   >
      {renderItem(item)}
  </div>

이것은 나를 위해 일했습니다!


답변

글로벌 이벤트 리스너를 갖고 싶었고 React Portal 사용으로 인해 이상한 동작이있었습니다. 문서 내의 포털 모달 구성 요소에서 취소 되었음에도 불구하고 문서 요소에서 이벤트가 계속 트리거되었습니다.

전체 구성 요소 트리를 래핑하는 루트 개체에서만 이벤트 리스너를 사용하는쪽으로 이동했습니다. 여기서 문제는 처음에는 본체가 루트 요소가 아니라 초점이 맞춰져 있으므로 트리 내의 요소에 초점을 맞추면 이벤트가 먼저 시작된다는 것입니다.

내가 찾은 해결책은 tabindex를 추가하고 효과 후크로 자동으로 초점을 맞추는 것입니다.

import React from "react";

export default GlobalEventContainer = ({ children, ...props }) => {
  const rootRef = React.useRef(null);
  useEffect(() => {
    if (document.activeElement === document.body && rootContainer.current)
      rootContainer.current.focus();
    }
  });

  return <div {...props} tabIndex="0" ref={rootRef}>{children}</div>
};


답변