react error TypeError: 未定義のプロパティ 'setState' を読み取ることができません。
コードは次のようになります。
class test extends Component {
constructor(props) {
super(props);
this.state = {
liked: false
};
}
handleClick(event) {
this.setState({liked: !this.state.liked});
}
render() {
var text = this.state.liked ? 'liked' : 'disliked';
return (
<div onClick={this.handleClick}>
You<b>{text}</b>me. Tap me to switch states.
</div>
);
}
}
export default test;
正常にページが表示できるようになります。
しかし、ボタンが押されるとエラーが報告されます。
なぜこのようなことが起こるのでしょうか?
なぜなら、ボタンをクリックしたとき、handleClick()メソッドでthisに到達する頃には、もうコンポーネント内ではthisではなくなっているからです。
最初の解決策は、これを手動でバインドすることです。
constructor(props) {
super(props);
this.state = {
liked: false
};
}
に変更する。
constructor(props) {
super(props);
this.state = {
liked: false
};
this.handleClick = this.handleClick.bind(this);//manual binding
}
2つ目の解決策は
handleClick(event) {
this.setState({liked: !this.state.liked});
}
に変更します。
handleClick= (e) => {
this.setState({liked: !this.state.liked});
}
この解決策で問題が解決したことで、別の疑問が生まれました。関数がReactコンポーネントのメソッドである場合、矢印関数と通常の関数の違いは何でしょうか?
例えば、以下の2つのaの定義はどう違うのでしょうか?
class App extends Component {
a() {
console.log(1)
}
a = () => {
console.log(1)
}
}
最初のaは、いうまでもなくprototypeメソッドの定義です。ルーズモードでのES5相当は
App.prototype.a = function() {}
2つ目は、ステージ2です。 パブリッククラスフィールド 中の書き方だと、babelの下では クラスプロパティの変換プラグイン でエスケープします。これに相当するのは
class App extends Component {
constructor (.. .args) {
super(... .args)
this.a = () => {
console.log(1)
}
}
}
なぜ第二の書き方が必要なのか?
Reactでは、クラスのprototypeメソッドをpropsで子コンポーネントに渡す場合、従来の書き方ではbind(this)が必要で、そうしないとメソッドを実行した時にthisが見つからない。
<button onClick={this.handleClick.bind(this)}></button>
または
<button onClick={(e) => this.handleClick(e)}></button>
これは醜く、ReactコンポーネントのshouldComponentUpdateの最適化に影響を及ぼします。
これは、ReactがshouldComponentUpdateを提供することで、開発者が不要なレンダリングを避けるための制御を行うためであり、React. PureComponentは、propsとstateの値が同じである限り、コンポーネントを再レンダリングすることはありません。
しかし、bind this を使用すると、親がレンダリングするたびに子に渡される props.onClick が変化し、手動で shouldComponentUpdate を実装しない限り、PureComponent の Shallow Compare は基本的に失敗します。
Public Class Fieldsを使ってこのように書けば、この問題は解決します。他にもプロトタイプメソッドを定義してコンストラクタ内でバインドしたり、デコレータを使ってバインドしたりと、いくつかの方法があります。
class A {
constructor() {
this.a = this.a.bind(this)
}
a() {}
// or
@bindthis
b() {}
}
そして arrow関数は、それ以外にもコードが少なくなっています。通常の関数との最大の違いは、関数が宣言された時点でこのスコープが定義されていることで、一般的には関数が宣言された時点で暗黙のうちにthisとして定義されています。
var a = ()=>{
console.log(this)
}
// equivalent to
var a = function(){
console.log(this)
}.bind(this);
a(); //Window
var b = function(){
console.log(this)
};
b(); //Window
var obj = { a,b };
obj.a(); //Window
obj.b(); //obj
詳しくは、以下の公式ドキュメントをご覧ください。 https://reactjs.org/docs/handling-events.html
関連
-
'node' は内部または外部のコマンド、操作可能なプログラムまたはバッチファイルとして認識されません。
-
android refactoring exceptionAndroid リソースリンクの失敗
-
C LanguageError:Idは1終了ステータスを返しました。
-
eclipseを起動中、エラー。スレッド "main" で例外発生 java.lang.
-
ruby がエラー Failed to build gem native extension を報告しました。
-
ternsflow AttributeError: __enter__
-
Oracle の例外 ORA-01861 を解決する: リテラルが形式文字列に一致しません。
-
S_ISREG S_ISDIR およびその他いくつかの共通マクロ
-
エラーが発生しました。ルールは1つのリソースソースしか持つことができません(提供されたリソースとテスト+インクルード+エクスクルード)。
-
STM32 学習 0 未定義識別子 "..." 使用時のエラー 解決方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
IIS 7.5上のASP.NET 4.0とチャートに関する質問
-
jinja2.exceptions.TemplateNotFound: xxxx.html
-
画像ダウンロードの問題
-
PythonのTypeError: unbound methodの問題を解決する
-
JAVA の小さな問題を解決する
-
raise JSONDecodeError("Expecting value", s, err.value) from None
-
Pythonの問題:SyntaxError:単一のステートメントをコンパイルする際に複数のステートメントが検出される
-
I encountered The markup in the document following the root element must be well-formed.
-
numpy.concatenate merge matrix エラー ValueError: すべての入力配列は同じ次元数でなければなりません。
-
ValueErrorの解決策:解凍する値が足りない(期待値2、取得値1)。