React基礎 Bind(バインド)方法と使い方
React クラスでのthis
Reactのクラスコンポーネントでthisをbindする必要がある理由は、JavaScriptの仕様に基づくものです。
まず、JavaScript本来のthisは実行方法によって参照先が変わります、ES6のJavaScriptのクラスメソッドのデフォルトはbind(バインド)はされておりません。
つまり関数・メソッド内ではthisという値が使えて、それは呼び出し方によって変化します。
JSメソッドは、そのメソッドが定義されたオブジェクトを参照するthisキーワードを持つ事になります。
しかし、Reactのクラスコンポーネントでは、イベントハンドラーなどのメソッドが、コンポーネントのインスタンスではなく、別のコンテキスト(例えばDOM要素やWindowオブジェクトなど)から呼び出されることがあります。
その場合、thisキーワードは予期しない値を参照する可能性があります。
JSXではメソッドをバインドする事によりJavaScript本来の動作と同じように実行されます。
Reactを使い始めた人は、イベントハンドラーにthisをバインドしていないというミスに出くわすはずです。
その問題に対する解決策を説明するために、以下のようなシンプルなコンポーネントを作成しました。
thisのバインドを持たないシンプルなクラスコンポーネントとなります。
ボタンクリック時undefinedエラーです。
class App extends React.Component { constructor (props) { super(props) this.state = { changeText: "変更前の表示です" } } ChangeBtn = () => { this.setState({ changeText: "変更された表示です" }); } render () { return ( <button onClick={this.ChangeBtn}> ボタン </button> ) } }
上記ではthis.ChangeBtnをバインドをせず、関数が呼ばれるとthisはundefinedエラーを返します。
バインドする前のthisの参照先が意図したものとは別のものになっている為undefinedが返ってきます。
それを、回避する為にthisをバインドしてあげます。
thisをbind(バインド)する
Reactには事前定義されたbind()メソッドがあり、これを使用してクラスベースのコンポーネントの関数に引数を渡すことができます。
constructor内でコンポーネントのthisにbindをします。
// エラー解決 class App extends React.Component { constructor (props) { super(props) this.state = { changeText: "変更前の表示です" } //thisのバインド this.ChangeBtn = this.ChangeBtn.bind(this) } ChangeBtn = () => { this.setState({ changeText: "変更された表示です" }); } render () { return ( <button onClick={this.ChangeBtn}> ボタン </button> ) } }
コールバックで実行したいメソッドthis.ChangeBtnを設定し、その後バインドをしChangeBtnメソッド内でのthisの参照先をクラスとしてバインドさせるという事になります。
※ 注意点はrenderメソッドやライフサイクルメソッドなどはバインドする必要はありません。
それらは他のコンポーネントに渡すことがないからです。
別の回避方法
前述では、constructor内でコンポーネントのthisにbindをすると言いましたが、必ずしもconstructor内である必要性はありません。
他の方法で回避をする例を見ていきましょう。
直接ボタンタグにBind()する
render () { return ( //バインド <button onClick={this.ChangeBtn.bind(this)}> ボタン </button> ) }
しっかり、バインドの引数にはthisを入れるのを忘れないようにしましょう。
イベントハンドラーでアロー関数を使用する
render () { return ( //アロー関数 <button onClick={ () => this.ChangeBtn() }> ボタン </button> ) }
イベントハンドラーでアロー関数を使用します。
呼び出す関数内のthisを現在のクラスインスタンスにもバインドされます。
上記のようにすることで、thisを自動的にバインドすることもできます。
こちらを使用する場合は、メソッドに引数の()をつけ忘れないように気をつけてください。
イベントハンドラーに引数を渡す
ChangeBtn = (e) => { this.setState({ changeText: "変更後の表示!!" }); } render () { return ( <button onClick={ (e) => this.ChangeBtn(e) }> ボタン </button> ) }
イベントハンドラーの引数にeを渡してあげます。
クラスコンポーネントでイベントハンドラーで値の変更する際はしっかりとconstructor内にbindしてあげるか、別の方法で回避をする事を忘れないようにして下さい。
ですが、なるべくconstructor内でイベントハンドラーをバインドして、インスタンスごとに1回だけバインドされるようにすることをお勧めします。
ThisのBindなぜ必要??
this.ChangeBtn = this.ChangeBtn.bind(this);
この行は一度に多くのことを行います。
Reactのイベントからクラスメソッドを呼び出すためになぜbind()を使用する必要があるのか疑問に思われるかもしれません。
thisはconstructorの中にあるので、他の何かではなくオブジェクトのインスタンスでなければならないので、信頼できるものです。
bindメソッドは関数ChangeBtnを受け取り、まったく同じことをする関数を返します。
ただし、関数の内部でオブジェクトのインスタンスが固定されていることが条件です。
新しい関数を既存のChangeBtnの代わりに割り当てます。
言いかえますと、新しい関数を割り当ててから既存のChangeBtnを置き換えます。
これにより、thisが呼び出されるたびに、どこから呼び出されても、オブジェクトインスタンスが使用され、他の値は使用される事がありません。
つまり、この新しい関数は、元の関数のコンテキストでthisキーワードを使用するように設定されます。
そして、ChangeBtn()メソッドが呼び出されたときに、thisが常にAppインスタンスを参照するようになります。
Reactのクラスコンポーネントでは、イベントハンドラーなどのメソッドを呼び出す前に、thisを明示的にバインドする必要があるという事は覚えておいて下さい。
本日は以上となります。
最後までこの記事を読んで頂きありがとうございます。