ゆったりWeb手帳

気になったことをのんびり書くよ

⚛️

ReactでonKeyPressを取得する

onKeyPress を取得する

onKeyPressはブラウザでキー入力されたときの動作を制御するために使います。

input で onKeyPress を取得する

例えば、inputタグで、入力後Enterを押して確定する動きをReactで実装すると以下のようになります。
React
const Component = ({text, changeText, sendText}) => {

  const keyPress = (e) => {
    if (e.which === 13) sendText()
    if (e.key === 'Enter') setChange()
  }

  return (
    <React.Fragment>
      <input type='text' value={text} onChange={(e) => changeText(e)} onKeyPress={(e) => keyPress(e)}>
    </React.Fragment>
  )
}
この例では、入力後Enterを入力すると入力された文字列が送信されます。IME変換確定時のEnterは無視されます。

div で onKeyPress を取得する

上記`input`のような場合は通常フォーカスされた状態で使用するので入力受付時も問題ないですが、そうではない場合は注意が必要です。
画面制御やメディアの再生、停止をキーボードでも操作できるようにするには親要素(`div`など)でイベントを拾わなければなりません。
この場合は、tabIndexを指定してマウントされたときにフォーカスするようにします。
React
const Component = ({mediaControl}) => {

  const keyPress = (e) => {
    if (e.which === 32) mediaControl() // スペースの入力を拾う
  }

  return (
    <React.Fragment>
      <div onKeyPress={(e) => keyPress(e)} tabIndex='0'>
        <AppComponent />
      </div>
    </React.Fragment>
  )
}
上記例では、スペースキーでメディアの再生を停止します。
しかし、AppComponent内にinputtextareaがある場合、イベントはバブリングするので文字列入力時のスペース入力も拾ってしまいます。
この場合は、フォーム要素での入力にevent.stopPropagation()メソッドを使うか、divでイベントを拾ったときに除外します。
React
const keyPress = (e) => {
  e.stopPropagation()
}
React
const keyPress = (e) => {
  if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') return false
  if (e.which === 32) mediaControl()
}

TypeScriptを使う

onKeyPressイベントのTypeScriptの型はKeyboardEvent<HTMLInputElement>です。
最初の例をTypeScriptで書くと以下のようになります。
React
const Component = ({text, changeText, sendText}) => {

  const keyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.which === 13) sendText()
  }

  return (
    <React.Fragment>
      <input type='text' value={text} onChange={(e) => changeText(e)} onKeyPress={(e) => keyPress(e)}>
    </React.Fragment>
  )
}

キーの判別

上記の例はキーのcharCodeを用いて判別を行なっていますが、キーのnamecodeなどで判別する方法もあります。
注意点はすべてのブラウザでキーのコードや名前が同じという保証はないので、実際に使用する場合は想定される環境で動作するか確認することをおすすめします。
次の記事nodeでパーミッションエラー