Bagaimana mendeteksi Esc Key Press di React dan bagaimana menanganinya


126

Bagaimana cara mendeteksi penekanan tombol Esc di reactjs? Hal yang mirip dengan jquery

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

Setelah terdeteksi saya ingin meneruskan info ke komponen. Saya memiliki 3 komponen yang komponen aktif terakhirnya perlu bereaksi terhadap tombol escape.

Saya sedang memikirkan semacam mendaftar ketika sebuah komponen menjadi aktif

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

dan di semua komponen

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

Saya percaya ini akan berhasil tetapi saya pikir ini akan lebih seperti panggilan balik. Apakah ada cara yang lebih baik untuk menangani ini?


Apakah Anda tidak memiliki implementasi fluks untuk menyimpan yang merupakan komponen aktif daripada melakukannya dengan cara ini?
Ben Hare

@ BenHare: Saya masih cukup baru untuk itu. Saya mencari kemungkinan untuk bermigrasi ke React. Saya belum mencoba fluks, jadi Anda menyarankan agar saya melihat fluks untuk solusinya. PS: Bagaimana dengan mendeteksi penekanan tombol ESC?
Neo

5
Hanya untuk memperjelas, apakah Anda mencari deteksi penekanan tombol pada tingkat dokumen, seperti blok kode pertama? Atau apakah ini untuk bidang masukan? Anda bisa melakukannya, saya hanya tidak yakin bagaimana membingkai jawaban. Berikut ini adalah contoh tingkat dokumen singkat: codepen.io/anon/pen/ZOzaPW
Brad Colthurst

Tingkat dokumen akan baik-baik saja :)
Neo

Jawaban:


229

Jika Anda mencari penanganan peristiwa kunci tingkat dokumen, maka mengikatnya selama componentDidMountadalah cara terbaik (seperti yang ditunjukkan oleh contoh codepen 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/>
    )
  }
}

Perhatikan bahwa Anda harus memastikan untuk menghapus key event listener saat unmount untuk mencegah potensi kesalahan dan kebocoran memori.

EDIT: Jika Anda menggunakan kait, Anda dapat menggunakan useEffectstruktur ini untuk menghasilkan efek yang serupa:

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
Apa argumen ketiga dalam addEventListenerdan removeEventListener?
jhuang


2
@jhuang itu adalah argumen useCapture yang menentukan apakah akan menangkap peristiwa yang biasanya tidak menggelembung atau tidakfocus . Ini tidak relevan untuk keydown, tetapi dulunya tidak opsional sehingga biasanya ditentukan untuk kompatibilitas dengan IE <9.
Chase Sandmann

Saya harus membungkus this.escFunctionke dalam fungsi seperti function() { this.escFunction(event) }, jika tidak itu dijalankan pada pemuatan halaman tanpa "keydown".
M3RS

2
Tidak perlu menyertakan 'false' sebagai argumen ke-3. Itu salah secara default.
NattyC

25

Anda akan ingin mendengarkan escape keyCode(27) dari 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 Brad Colthurst yang diposting di komentar pertanyaan berguna untuk menemukan kode kunci untuk kunci lain.


15
Saya rasa ada baiknya menambahkan bahwa React tampaknya tidak mengaktifkan onKeyPressevent ketika tombol yang ditekan adalah ESC dan fokus ada di dalam <input type="text" />. Dalam skenario itu, Anda dapat menggunakan onKeyDowndan onKeyUp, keduanya menembak, dan dalam urutan yang benar.
Tom

12

Cara lain untuk melakukannya dalam komponen fungsional, adalah dengan menggunakan useEffectdan useFunction, seperti ini:

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

Alih-alih console.log, Anda dapat menggunakan useStateuntuk memicu sesuatu.


7

React menggunakan SyntheticKeyboardEvent untuk membungkus event browser asli dan event Synthetic ini menyediakan atribut key bernama ,
yang bisa Anda gunakan seperti ini:

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
fakta menarik jika Anda perlu mendukung IE9 dan / atau Firefox 36 atau lebih rendah, e.keyuntuk Escapekembali lagi sebagai Esc#triggered
Agustus

4

Untuk solusi hook React yang dapat digunakan kembali

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

Pemakaian:

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

3
Solusinya tidak memungkinkan untuk mengubah fungsi onEscape. Anda harus useMemo dan meneruskan onEscape sebagai dep array untuk useEffect
Neo
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.