⌨️

Reactでkeydownイベントを取得する方法

2020/09/20に公開約900字2件のコメント

はい、みなさんこんにちは。
Reactで入力されたキーが何か判定したくなったことってありませんか?

やってみるとちょっとコツがいったので、まとめておきます。

サンプルコード

import React, { useEffect, useCallback } from "react";

export default function App() {
  const escFunction = useCallback((event) => {
    if (event.keyCode === 27) {
      // キーコードを判定して何かする。
      console.log("Esc Key is pressed!");
    }
  }, []);

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

  return <input />;
}

CodeSandbox

https://codesandbox.io/s/listenkeydown-50ob8?file=/src/App.js

解説

ポイントは、グローバル変数の documentです。

useEffectの第二引数に空配列を指定すると、コンポーネントマウント時に1度だけ呼びされます。そのタイミングで、addEventListenerでコールバック関数を登録しています。

ちょっと意外なやり方ですが、これでVanilla Javascriptと同じようにイベントを取得できますね。

参考URL

https://stackoverflow.com/questions/37440408/how-to-detect-esc-key-press-in-react-and-how-to-handle-it/46123962
キーコード一覧
https://web-designer.cman.jp/javascript_ref/keyboard/keycode/

Discussion

useEffectの記述ですが、

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

↓↓↓ ではなく

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

escFunction呼び出し時にuseCallbackする意味がなくなってしまうので、
第2引数にescFunctionを渡しておくべきだと思います。

addEventListenerを使うときは対でremoveEventListenerも呼んだ方が良いと思います(そうでないと、コンポーネントが破棄された後もescFunctionが呼び出され続けます。リークの一種です)

useEffectにはそういった場合の為にクリーンアップ関数を返せるようになっていますので

https://ja.reactjs.org/docs/hooks-effect.html#effects-with-cleanup

下記のコードがより適切かなと思いました

useEffect(() => {
  document.addEventListener("keydown", escFunction, false);
  return () => {
    document.removeEventListener("keydown", escFunction, false);
  }
}, [escFunction]);
ログインするとコメントできます