React公式ドキュメントを読む16 Reactでのイベント指定

前回からの続きですが、このページだけ読んでも分かる内容になっています。 今回読むReact公式ドキュメントは「イベント処理」のページです。

Reactでのイベント指定は、HTMLコードにJavaScriptのイベントを指定するのとは書き方が少し異なります。Reactでのイベント指定について見ていきましょう。

標準のHTMLコードによるイベント指定方法との違い

Reactでのイベント指定方法は、標準のHTMLやJavaScriptによるイベント指定方法とは少し異なります。例えば、HTMLでは以下のようにイベントを記述します。

<button onclick="activateLasers()">
  Activate Lasers
</button>

上記のコードでは、ボタン要素がクリックされたら、activateLasers()関数を呼ぶように指定しています。一方、Reactにおいて同じ指定をJSXで記述すると、以下のコードになります。

<button onClick={activateLasers}>
  Activate Lasers
</button>

これらのコードはよく似ていますが、2点の違いがあります。

1つめの違いは、イベントの記述形式です。HTMLでは「onclick」とすべて小文字で記述していますが、JSXでは「onClick」とキャメルケースで記述しています。これは、Reactイベントがキャメルケースで名付けられているためです。

2つめの違いは、イベントが起きたときに渡される内容です。HTMLでは”activateLasers()”と関数名をダブルクォーテーション( ” )で囲んで文字列として渡していますが、JSXでは{activateLasers}と中括弧で囲んで関数そのものを渡しています。

  • Reactイベントは、小文字ではなくキャメルケースで名付けられています。
  • JSXでは、文字列ではなく関数をイベントハンドラとして渡します。

Reactでは return false と書いてもリンクのデフォルト動作を止められない

例えば、HTMLコードでは、「新しいページを開く」というリンクのデフォルト動作をさせないために、falseを使って以下のように記述できます。以下のHTMLコードでは、<a>タグによるリンクに return falseと記述したことで、リンクをクリックしてもリンク先ページへジャンプしなくなります。

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

一方、Reactで上記と同じ動作をする指定をJSXで記述する場合、例えば以下のようなコードになります。上のHTMLコードとかなり違っていますが、Reactではreturn false が使えないので別の書き方をする必要があるためです。

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

上記コードの3行目にある e.preventDefault(); に注目してください。 HTMLコードでは return false と書けばリンクのデフォルト動作を止められますが、Reactでは return false と書いてもリンクのデフォルト動作を止められません。

そのためReactでは、preventDefault() を使ってリンクのデフォルト動作を止めています。preventDefault()メソッドはW3Cの仕様で定義されているもので、デフォルト動作をキャンセルする際に使用します。

ReactでES6のクラスを使用してコンポーネントを作成した場合

ReactでES6のクラスを使用してコンポーネントを作成した場合、イベントハンドラはクラスのメソッドとして作成するのが一般的です。そして、 イベントハンドラをクラスのメソッドとして作成した場合、一般的には バインドしてやる必要があります。

以下のコードで、実例を見てみましょう。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    // 初期値を true に設定して state に代入
    this.state = {isToggleOn: true};
    // コールバックで「this」を機能させるためにバインドが必要
    this.handleClick = this.handleClick.bind(this);
  }

  // クリックされたら state を切り替える
  // イベントハンドラは、クラスのメソッドとして作成されている
  handleClick() {
    // 以下の「this」を定義するために上でバインドしている
    // そうでなければ、以下の「this」は undefined となってしまう
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

上記のサンプルソースをHTMLファイルにしたものが以下です。

https://programming-world.net/sample/react_handling-events1-1.html

上記のサンプルが実行されると、画面には[ON]ボタンが表示されて、ボタンを押すたびに[ON]と[OFF]が交互に切り替わります。この [ON]と[OFF] のボタンをレンダリングしているのは、ES6のクラスを使用して作成されたToggleコンポーネントです。

上記のサンプルでは、クリックされたら state を切り替えるイベントハンドラが、handleClick()というメソッドとして作成されています。このメソッドは this.setState()で state の値を更新して [ON]と[OFF] を切り替えます。

尚、JavaScriptでは、クラスのメソッドはデフォルトではバインドされません。そのため、上記コードではコンストラクタのなかの this.handleClick = this.handleClick.bind(this); の行でバインドしています。そうすることで handleClick() のなかの「this」が何を指しているのか明確になります。

バインドしないでパブリッククラスフィールド構文を使用する書き方もある

イベントハンドラをクラスのメソッドとして作成した場合、上の例のように bind の呼び出してメソッドをバインドするのが一般的な書き方ですが、バインドしないでパブリッククラスフィールド構文を使用する書き方もあります。

以下のコードは、パブリッククラスフィールド構文を使用した書き方の例です。

class LoggingButton extends React.Component {
  // 以下の構文により、「this」がhandleClick内にバインドされます。
  // ただし、これは“実験的な”構文です。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

上記コードのように、パブリッククラスフィールド構文を使用した書き方をすれば bind を呼び出す必要はありません。ただし、パブリッククラスフィールド構文は“実験的な”構文である点に注意してください。

パブリッククラスフィールド構文は、Create React App を利用する場合にはデフォルトで有効なので、状況次第で利用を検討しても良いでしょう。

次回へ続きます。