「TypeError: Cannot read property ‘state’ of undefined」に出会ったらJavascriptの”this”について真剣に考えよう

Javascriptのthisは本当にわかりにくい

<form className="ui form" onSubmit={this.onFormSubmit}>

で呼んだonFormSubmit関数でエラーがでる。

onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

console.log(this.state.term);のところで「TypeError: Cannot read property 'state' of undefined」がでる

「undefinedのプロパティ'state'を読み込むことができない」

いやいやいや

undefinedじゃないよthisだよthis何を言ってるのJavascriptさん

全部のコードはこんな感じ

import React from 'react';

class SearchBar extends React.Component {
  state = { term: '' };

  onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

  render() {
    return (
      <div className="ui segment">
        <form className="ui form" onSubmit={this.onFormSubmit}>
          <div className="field">
            <label htmlFor="">画像を検索</label>
            <input
              type="text"
              value={this.state.term}
              onChange={e => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

export default SearchBar;

<form className="ui form" onSubmit={this.onFormSubmit}>

で this.onFormSubmitを呼び出しているonFormSubmit関数内でstateオブジェクトにアクセスしようとしましたが・・・・・エラー

これは呼び出しているのがコールバック関数のため、thisがどのthisになっているかということ

解決方法1. bindでthisのオブジェクトをひも付ける

onSubmit={this.onFormSubmit}の問題点は、コールバック関数が実行されるときにthisが渡されないことです。
単純にonFormSubmit関数が実行されます。
ですので、bindでthisを明示的にひも付けます。

<form className="ui form" onSubmit={this.onFormSubmit.bind(this)}>

この方法はレガシーな(古い)方法です。
最近では以下で紹介する方法がよく使われます。

解決方法2.アロー関数は自動的にthisの値をbindする

onFormSubmit = event => {
    event.preventDefault();
    console.log(this.state.term);
  };

アロー関数は自動的にthisの値をbindしてくれます。

onFormSubmitをアロー関数で定義します。

アロー関数はES6から利用できる機能ですが、アロー関数でクラス内のメソッドを書けば、thisが行方不明になる問題は起きなくなるということです。

今時のReact開発環境ではES6に対応しているので、この方法がいいですね。

解決方法3.onSubmit内をアロー関数に変更する

onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

関数はそのままで呼び出す側をアロー関数にかえる方法もあります
<form className="ui form" onSubmit={event => this.onFormSubmit(event)}>
呼び出す方法をアロー関数に変更しました。

コメント