Come rilevare la pressione del tasto Esc in React e come gestirla


126

Come si rileva la pressione del tasto Esc su reactjs? La cosa simile a jquery

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

Una volta rilevato, voglio passare le informazioni ai componenti. Ho 3 componenti di cui l'ultimo componente attivo deve reagire alla pressione del tasto Esc.

Stavo pensando a una sorta di registrazione quando un componente diventa attivo

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>
    )
  }
}

e su tutti i componenti

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)}/>
    )
  }
}

Credo che funzionerà, ma penso che sarà più come un richiamo. C'è un modo migliore per gestire questo?


Non hai alcuna implementazione del flusso per memorizzare quale sia il componente attivo invece di farlo in questo modo?
Ben Hare

@ BenHare: sono ancora abbastanza nuovo. Sto esaminando la fattibilità della migrazione in React. Non ho provato il flusso, quindi stai suggerendo che dovrei cercare la soluzione nel flusso. PS: che ne dici di rilevare la pressione dei tasti ESC?
Neo

5
Giusto per chiarire, stai cercando il rilevamento della pressione dei tasti a livello di documento, come il primo blocco di codice? O è per un campo di input? Puoi fare entrambe le cose, solo che non sono sicuro di come inquadrare una risposta. Ecco un breve documento a livello di esempio: codepen.io/anon/pen/ZOzaPW
Brad Colthurst

Il livello del documento andrebbe bene :)
Neo

Risposte:


229

Se stai cercando una gestione degli eventi chiave a livello di documento, componentDidMountil modo migliore è vincolarlo durante (come mostrato dall'esempio di codepen di Brad Colthurst ):

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/>
    )
  }
}

Nota che dovresti assicurarti di rimuovere il listener di eventi chiave allo smontaggio per prevenire potenziali errori e perdite di memoria.

MODIFICA: se stai usando i ganci, puoi usare questa useEffectstruttura per produrre un effetto simile:

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
Qual è il terzo argomento in addEventListenere removeEventListener?
jhuang

2
@jhuang developer.mozilla.org/en-US/docs/Web/API/EventTarget/… - possono essere otions ou useCapture
Julio Saito

2
@jhuang è l'argomento useCapture che specifica se acquisire o meno eventi che di solito non si manifestano comefocus . Non è rilevante per keydown, ma in passato non era opzionale, quindi di solito è specificato per la compatibilità con IE <9.
Chase Sandmann

Ho dovuto avvolgere this.escFunctionin una funzione del tipo function() { this.escFunction(event) }, altrimenti veniva eseguita al caricamento della pagina senza alcun "tasto".
M3RS

2
Non è necessario includere "false" come terzo argomento. È falso per impostazione predefinita.
NattyC

25

Ti consigliamo di ascoltare escape keyCode(27) da 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 di Brad Colthurst pubblicato nei commenti della domanda è utile per trovare codici chiave per altre chiavi.


15
Penso che valga la pena aggiungere che React sembra non attivare l' onKeyPressevento quando il tasto premuto è ESC e il focus è all'interno <input type="text" />. In quello scenario, puoi usare onKeyDowne onKeyUp, entrambi sparano e nell'ordine corretto.
Tom

12

Un altro modo per ottenere ciò in un componente funzionale è utilizzare useEffecte useFunction, in questo modo:

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>);
}

Invece di console.log, puoi usare useStateper attivare qualcosa.


7

React usa SyntheticKeyboardEvent per avvolgere l'evento del browser nativo e questo evento sintetico fornisce l' attributo chiave denominato ,
che puoi usare in questo modo:

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
divertimento Infatti se si ha bisogno di supportare IE9 e / o Firefox 36 o al di sotto, e.keyper Escaperitorna come Esc#triggered
Agosto

4

Per una soluzione di gancio React riutilizzabile

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

Uso:

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

3
La soluzione non consente il cambio della funzione onEscape. Dovresti usareMemo e trasmettereEscape come array di dep per useEffect
Neo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.