はじめてのReact #8「イベント処理を試してみよう」

イベント処理は、タグ内にonClickなどのイベントハンドラ用の属性を指定することで定義できます。

これだけ聞くと正直気持ち悪いですよねw 結論から言うと最終的には問題ない形でレンダリングされます。実際のサンプルコードを元に話を進めていきましょう。

おみくじComponent

今回はボタンをクリックすると、運勢がアラートされる簡単な「おみくじ」を作成してみたいと思います。

サンプル

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>おみくじ</title>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

  <!-- Don't use this in production: -->
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>

  <script type="text/babel">
    class Omikuji extends React.Component {
      dropOmikuji(e){
        let unsei = ["大吉", "吉", "中吉", "小吉", "凶", "大凶"];
        let i = Math.ceil(Math.random() * 100) % unsei.length;

        alert(`あなたの運勢は${unsei[i]}です`);  // ``内に ${} で変数を埋め込めるのはES2015からの追加仕様
      }

      render() {
        return <button onClick={this.dropOmikuji}>おみくじを引く</button>;
      }
    }

    ReactDOM.render(
      <Omikuji />,
      document.getElementById('root')
    );
  </script>
</body>
</html>

実行結果

以下のようにボタンが表示され、

クリックすると運勢が表示されるアラートが飛び出します。

解説

onClick属性とかいつの時代だと感じた方へ

最近のJavaScriptでは以下のようにaddEventListenerでイベント発生時の処理を定義することが主流で、onClickなどのイベント属性内に書くことは推奨されていません。Reactを初見で気持ち悪いと感じる一つの要因かと思います。

document.querySelector("#foo").addEventListener("click", ()=>{
  //何らかの処理
});

結論から言うとReact…というかJSXでは、実際にレンダリングされる際にはaddEventListenerに置き換わるようです。出力されたコードを見てみると、以下のようにonClickが跡形もなく消えているのがわかると思います。ご安心ください。

<div id="root">
  <button>おみくじを引く</button>
</div>

任意の値を渡す

今回のサンプルのように onClick={this.methodname} といった、ボタンが押されたら何らかの決まった処理をするだけであれば問題にならないのですが、任意の引数をメソッドや関数に渡したい場合は、以下のようにJavaScriptの機能であるbindを利用します。

class Omikuji extends React.Component {
  dropOmikuji(name, e){
    let unsei = ["大吉", "吉", "中吉", "小吉", "凶", "大凶"];
    let i  = Math.ceil(Math.random() * 10) % unsei.length;

    alert(`${name}さんの運勢は${unsei[i]}です`);
  }

  render() {
    return <button onClick={this.dropOmikuji.bind(this, "foo")}>おみくじを引く</button>;
  }
}

実行すると以下のように名前を渡すことができました。

その他にも、クロージャー(無名関数)を利用することもできます。以下ではES2015で登場したアロー関数を用いています。

class Omikuji extends React.Component {
  dropOmikuji(name){
    let unsei = ["大吉", "吉", "中吉", "小吉", "凶", "大凶"];
    let i  = Math.ceil(Math.random() * 10) % unsei.length;

    alert(`${name}さんの運勢は${unsei[i]}です`);
  }

  render() {
    return <button onClick={()=>{ this.dropOmikuji("foo") } }>おみくじを引く</button>;
  }
}

その他のイベント

今回はonClickだけ試しましたが、同じ要領で他のイベントも定義することが可能です。一般的なJavaScriptのイベントハンドラは利用することができるようです。以下のコードでマウスオーバーとマウスアウトのイベントも同時に捕捉することができます。

class Omikuji extends React.Component {
  dropOmikuji(name, e){
    let unsei = ["大吉", "吉", "中吉", "小吉", "凶", "大凶"];
    let i  = Math.ceil(Math.random() * 10) % unsei.length;

    alert(`${name}さんの運勢は${unsei[i]}です`);
  }
  overOmikuji(){
    console.log("マウスオーバー");
  }
  outOmikuji(){
    console.log("マウスアウト");
  }

  render() {
    return(
      <button onClick={this.dropOmikuji.bind(this, "foo")}
              onMouseOver={this.overOmikuji}
              onMouseOut={this.outOmikuji} >
        おみくじを引く
      </button>
    );
  }
}

注意点

本来の要素の動作をキャンセルしたい

今回のサンプルでは<button>要素を使いましたが、例えば<a>要素だった場合には、ボタンをクリックするとイベント処理が終了したと同時に画面遷移が発生してしまいます。

  render() {
    return <a href="https://google.com/" onclick={this.dropOmikuji}>おみくじを引く</a>;
  }

これを防ぐためには以下のようにpreventDefault()を実行してやるだけです。試しに当該行をコメントアウトや削除すると、アラートが出たあとにGoogleへと遷移するのが確認できると思います。もちろん意図した物であれば問題ありません。

class Omikuji extends React.Component {
  dropOmikuji(name, e){
    e.preventDefault();

    let unsei = ["大吉", "吉", "中吉", "小吉", "凶", "大凶"];
    let i  = Math.ceil(Math.random() * 10) % unsei.length;

    alert(`${name}さんの運勢は${unsei[i]}です`);
  }

  render() {
    return <a href="https://google.com" onClick={this.dropOmikuji.bind(this, "foo")}>おみくじを引く</a>;
  }
}

大文字と小文字は区別される

以下のように onCllick ではなくすべて小文字で onclick と書くと警告が出ます。

  render() {
    return <button onclick={this.dropOmikuji}>おみくじを引く</button>;
  }
Warning: Invalid event handler property `onclick`. Did you mean `onClick`?

このように大文字と小文字は区別されますのでご注意を。JSXがHTMLではなくXMLベースの仕様であることを再確認させられますねw

少括弧をうかつに付けない

以下のようにメソッド名の後ろに少括弧を書いてしまうと、イベント発生時ではなくrender()時に実行されてしまいます。意図したものなら良いですがご注意を。

  render() {
    return <button onClick={this.dropOmikuji()}>おみくじを引く</button>;
  }

書籍

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)
穴井 宏幸 石井 直矢 柴田 和祈 三宮 肇
翔泳社
売り上げランキング: 139,067

参考ページ

reactjs.org