Help us understand the problem. What is going on with this article?

React TutorialのTick-Tock-Toeを題材に、ReactでのEvent Handlingを理解する

More than 1 year has passed since last update.

まとめ

Reactのチュートリアルを読んでいて、onClickでのイベントハンドリング部分のコードが理解できず、3日間悩んだ。二つのポイントで誤解してハマっていたのでメモ。

中々理解できなかった箇所

Square, Board, Gameと3つのコンポーネント間で、ユーザのマウスクリックイベントをどう伝えていくか。
具体的には以下のコード。
React TutorialのCodePenコード

// Square Class
<button className="square" onClick={props.onClick}>
  {props.value}
</button>
// Board Class
<Square
  value={this.props.squares[i]}
  onClick={() => this.props.onClick(i)}
/>
// Game Class
<Board
  squares={current.squares}
  onClick={i => this.handleClick(i)}
/>

誤解していたポイント

  1. HTMLでの作法と同様に、onClick属性には関数の実行文を与える
  2. 以下のアロー関数は、関数を返す関数である
const func = () => console.log("asdf")

誤解ポイント1

JSXで指定するonClick属性には、HTMLでの作法と同様に、関数の実行文を与えるべき。
これが間違っていた。
HTMLでは以下のように関数の実行文をonClick属性に与える。

<button onClick="console.log('hoge')"/>

JSXでもこれに習って実行文を与えるものと思っていたが、JSXでは実行文ではなく、関数を与えると内部で実行してくれる模様。下記コードが実例で、onClick={this.handler}において関数定義を与えるだけで、関数が実行されてhogeが表示される。

class Hoge extends React.Component{
    handler(){
        console.log("hoge");
    }
    render(){
        return(
            <button onClick={this.handler}/>  /* マウスクリックでhogeが表示される */
        );
    }
}

このHTMLとJSXの仕様の差に気づかず、React/JSXのコードを読んで、「このコードでいつ誰が関数を実行しているんだろう」と悩んでいたが、React/JSXでは関数定義を与えると内部で実行される模様。

誤解ポイント2

ポイント1の誤解に気づいてonClickには関数定義を与えれば良いと分かり、Square ClassのonClick={props.onClick]は理解できた。
しかし、Game ClassのonClick={i => this.handleClick(i)}は関数定義でなく関数の実行をしているように(何故か)誤解して、両者の違いに悩んだ。
結局はアロー関数のreturnの省略出来るケースに気づいて、Game Classでも関数の定義をonClickに渡しているだけだ、とようやく理解できた。

//昔ながらの形式
function func(arg){
  return console.log(arg)
}
//アロー関数
const funcAllow = (arg) => console.log(arg)

returnという予約語を見慣れていたこと、アロー関数の省略記法に慣れてなかった事が誤解につながったんだと思う。

  • 関数の定義:funcA
var funcA = function(){
  console.log("asdf");
}
  • 関数を返す、関数の定義:funcB
var funcB = function(){
  return function(){
    console.log("asdf");
  }
}
  • 実行文を返す、関数の定義:funcC
    【2018/6/21追記】「実行文を返す」でなく「実行結果を返す」の方が一般的で分かりやすい。
var funcC = function(){
  return console.log("asdf");
}

これらをES6の表記に直してみると、以下のようになる。違いが分かりづらい。

const funcA = () => {console.log("asdf")}
const funcB = () => () => console.log("asdf")
const funcC = () => console.log("asdf")
ya9do
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away