Як виявити натискання клавіші Esc в React і як з цим впоратися


124

Як виявити натискання клавіш Esc на reactjs? Схожа річ на jquery

$(document).keyup(function(e) {
     if (e.keyCode == 27) { // escape key maps to keycode `27`
        // <DO YOUR WORK HERE>
    }
});

Після виявлення я хочу передати інформацію вниз компонентів. У мене є 3 компоненти, з яких останній активний компонент повинен реагувати на натискання клавіші втечі.

Я думав про своєрідну реєстрацію, коли компонент стає активним

class Layout extends React.Component {
  onActive(escFunction){
    this.escFunction = escFunction;
  }
  onEscPress(){
   if(_.isFunction(this.escFunction)){
      this.escFunction()
   }
  }
  render(){
    return (
      <div class="root">
        <ActionPanel onActive={this.onActive.bind(this)}/>
        <DataPanel onActive={this.onActive.bind(this)}/>
        <ResultPanel onActive={this.onActive.bind(this)}/>
      </div>
    )
  }
}

і на всіх компонентах

class ActionPanel extends React.Component {
  escFunction(){
   //Do whatever when esc is pressed
  }
  onActive(){
    this.props.onActive(this.escFunction.bind(this));
  }
  render(){
    return (   
      <input onKeyDown={this.onActive.bind(this)}/>
    )
  }
}

Я вважаю, що це спрацює, але я думаю, це буде більше схоже на зворотний дзвінок. Чи є кращий спосіб впоратися з цим?


Чи немає у вас реалізації флюсу, щоб зберігати активний компонент, а не робити це таким чином?
Бен Заєць

@BenHare: Я все ще досить новий. Я розглядаю можливість міграції в React. Я не пробував флюс, тому ви пропонуєте мені шукати розчин для розробки. PS: Як щодо виявлення клавіші ESC?
Нео

5
Щоб уточнити, чи шукаєте ви виявлення натискання клавіш на рівні документа, як перший блок коду? Або це для поля введення? Ви можете зробити будь-яке, я просто не впевнений, як оформити відповідь. Ось швидкий рівень документа, наприклад: codepen.io/anon/pen/ZOzaPW
Бред Колтерст

Рівень документа буде добре :)
Нео

Відповіді:


229

Якщо ви шукаєте обробку ключових подій на рівні документа, то прив'язка його під час componentDidMount- найкращий спосіб (як показано в прикладі кодексу Бреда Колтурста ):

class ActionPanel extends React.Component {
  constructor(props){
    super(props);
    this.escFunction = this.escFunction.bind(this);
  }
  escFunction(event){
    if(event.keyCode === 27) {
      //Do whatever when esc is pressed
    }
  }
  componentDidMount(){
    document.addEventListener("keydown", this.escFunction, false);
  }
  componentWillUnmount(){
    document.removeEventListener("keydown", this.escFunction, false);
  }
  render(){
    return (   
      <input/>
    )
  }
}

Зауважте, що ви повинні обов’язково видалити прослуховувач ключових подій на вимкнено, щоб уникнути можливих помилок та витоку пам'яті.

EDIT: Якщо ви використовуєте гачки, ви можете використовувати цю useEffectструктуру для отримання подібного ефекту:

const ActionPanel = (props) => {
  const escFunction = useCallback((event) => {
    if(event.keyCode === 27) {
      //Do whatever when esc is pressed
    }
  }, []);

  useEffect(() => {
    document.addEventListener("keydown", escFunction, false);

    return () => {
      document.removeEventListener("keydown", escFunction, false);
    };
  }, []);

  return (   
    <input />
  )
};

7
Що таке третій аргумент addEventListenerі removeEventListener?
jhuang

2
@jhuang developer.mozilla.org/en-US/docs/Web/API/EventTarget/… - можуть бути відмовлені або використовуватиCapture
Julio Saito

2
@jhuang - це аргумент UseCapture, який визначає, чи потрібно фіксувати події, які зазвичай не перетворюються на зразокfocus . Це не стосується для keydown, але він раніше не був необов'язковим, тому зазвичай він задається для сумісності з IE <9.
Чейз Сандман

Мені довелося this.escFunctionперетворитись на функцію на кшталт function() { this.escFunction(event) }, інакше вона виконується при завантаженні сторінки без будь-якого «клавішного».
M3RS

2
Не потрібно включати "false" в якості 3-го аргументу. За замовчуванням це неправда.
NattyC

25

Ви хочете послухати втечі keyCode(27) від ReactSyntheticKeyBoardEvent onKeyDown :

const EscapeListen = React.createClass({
  handleKeyDown: function(e) {
    if (e.keyCode === 27) {
      console.log('You pressed the escape key!')
    }
  },

  render: function() {
    return (
      <input type='text'
             onKeyDown={this.handleKeyDown} />
    )
  }
})

CodePen Бреда Колтурста, розміщений у коментарях до запитання, корисний для пошуку ключових кодів інших клавіш.


15
Я думаю, що варто додати, що, як видається, React не спрацьовує onKeyPressподії, коли натиснута клавіша - ESC, а фокус знаходиться всередині <input type="text" />. У цьому сценарії ви можете використовувати onKeyDownі те onKeyUp, і вогонь, і в правильному порядку.
Том

12

Інший спосіб досягти цього у функціональному компоненті - це використання useEffectта useFunction, як це:

import React, { useEffect } from 'react';

const App = () => {


  useEffect(() => {
    const handleEsc = (event) => {
       if (event.keyCode === 27) {
        console.log('Close')
      }
    };
    window.addEventListener('keydown', handleEsc);

    return () => {
      window.removeEventListener('keydown', handleEsc);
    };
  }, []);

  return(<p>Press ESC to console log "Close"</p>);
}

Замість console.log ви можете використовувати, useStateщоб щось запустити.


7

React використовує SyntheticKeyboardEvent для загортання події на власному веб-переглядачі, і ця подія Synthetic надає найменування ключового атрибута ,
який ви можете використовувати так:

handleOnKeyDown = (e) => {
  if (['Enter', 'ArrowRight', 'Tab'].includes(e.key)) {
    // select item
    e.preventDefault();
  } else if (e.key === 'ArrowUp') {
    // go to top item
    e.preventDefault();
  } else if (e.key === 'ArrowDown') {
    // go to bottom item
    e.preventDefault();
  } else if (e.key === 'Escape') {
    // escape
    e.preventDefault();
  }
};

3
Цікавий факт , якщо вам необхідно підтримувати IE9 і / або Firefox 36 або нижче, e.keyдля Escapeповертається як Esc#triggered
Серпня

4

Для рішення для гачка React для багаторазового використання

import React, { useEffect } from 'react';

const useEscape = (onEscape) => {
    useEffect(() => {
        const handleEsc = (event) => {
            if (event.keyCode === 27) 
                onEscape();
        };
        window.addEventListener('keydown', handleEsc);

        return () => {
            window.removeEventListener('keydown', handleEsc);
        };
    }, []);
}

export default useEscape

Використання:

const [isOpen, setIsOpen] = useState(false);
useEscape(() => setIsOpen(false))

3
Рішення не дозволяє змінювати функцію onEscape. Вам слід скористатись пам'яткою і передати onEscape як масив dep для useEffect
Neo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.