Reactでイベントを処理する新しい方法
*「プロパティ初期化構文」*は実際よりも派手に聞こえます。 この一口サイズのチュートリアルでは、イベントハンドラーを作成するこの代替方法が、ボイラープレートを排除するのにどのように役立つかを確認してください。 constructor
また、レンダリングでの軽薄なメモリ使用を防ぎます。
Facebookのドキュメントでは、次のようにイベント処理が行われていることがわかります。
// option 1
class Thing extends React.Component {
constructor() {
this.handleSmthng = this.handleSmthng.bind(this)
}
render() {
<input onChange={this.handleSmthng}/>
}
handleSmthng(e) {
// ...
}
}
ES6クラスは自動的に提供しません this
スコープ handleSmthng
、そしてあなたは通常電話したくなるので this.setState
または、コンポーネントで別のメソッドを呼び出す場合、「公式」の規則は、コンストラクターで常にすべてのイベントハンドラーをバインドすることです。 これは機能しますが、すぐにボイラープレートコードのように感じることがあります。
// option 2
class Thing extends React.Component {
render() {
<button onClick={() => this.handleSmthng('foo')}>
ADD
</button>
}
handleSmthng(arg1) {
// ...
}
}
このパターンは、オンラインのReactチュートリアルで人気が高まっているようです。 合格します this
コンテキスト handleSmthng
コンストラクターの定型コードを回避します。 このコンポーネントには状態がないので、コンストラクターも必要ありません。 このアプローチの動機は正しいと思います…しかし、わずかなパフォーマンスコストがあります。
矢印関数を使用すると、JavaScriptで常に新しい参照が作成され、アプリのメモリ使用量が増加します。 JavaScriptではメモリは安価ですが、Reactではレンダリングにコストがかかります。 矢印関数を子コンポーネントに渡すと、その矢印関数は新しいデータであるため、子コンポーネントは無差別に再レンダリングされます。 これは、大規模なReactアプリケーションで60fpsと50fpsを取得することの違いを意味する可能性があります。
「…しかし、このコールバックが下位コンポーネントへの小道具として渡された場合、それらのコンポーネントは余分な再レンダリングを行う可能性があります。」 Reactドキュメント
2つのバインド1つのクロージャー
1)ボイラープレートを回避し、2)余分な再レンダリングを引き起こさないイベントハンドラーを作成するためのはるかにクリーンな方法があります:プロパティ初期化構文! 派手な名前ですが、アイデアは本当に単純です…矢印関数を使用してイベントハンドラーを定義するだけです。 このような:
class TodoApp extends React.Component {
render() {
return (
<div>
<button onClick={this.handleClick}>
ADD
</button>
<input onChange={this.handleInput}/>
</div>
);
}
handleClick = () => {
// "this"
}
handleInput = (e) => {
// "this", "e"
}
}
あなたは2つのハンドラーを定義しました、そしてそれは本当に素晴らしく見えます。 ボイラープレートはありません。 読みやすい。 リファクタリングが簡単…引数を渡したい場合:
class TodoApp extends React.Component {
render() {
return (
<div>
<button onClick={this.handleClick}>
ADD
</button>
<input onChange={this.handleInput}/>
{
this.state.todos.map((item) => {
return (
<li onClick={this.handleRemove(item.id)}>
{item.text}
</li>
);
});
}
</div>
)
}
handleClick = () => {
// "this"
}
handleInput = (e) => {
// "this", "e"
}
handleRemove = (id) => (e) => {
// "this", "e", "id"
}
}
ブーム! 使用せずに引数を渡すことができます bind
レンダリングメソッド、またはコンストラクターで! すべてが本当に刺激的でスパンに見えます。
矢印の機能を見ることに慣れていない場合、これはおそらく奇妙に見えます。 ES6では、太い矢印の構文により、1行のステートメントで中括弧を省略できることを覚えておいてください…暗黙的に return
その行に何でも! これがバベルがトランスパイルする方法です handleRemove
:
handleRemove: function (item) {
return function (e) {
// "item" AND "e" 🌈
}
}
プロパティ初期化構文を使用するようにBabelを設定するには、「transform-class-properties」プラグインまたは enablestage-2がインストールされていることを確認してください。 「create-react-app」を使用している場合…すでにあります!
レンダリングで「バインド」または矢印機能を使用しないように指示するESLintルールがあります
プロパティ初期化構文を使用する利点
Facebookがドキュメントでこのパターンを「公式に」承認していないのは、ステージ2 ES6がまだ完成していないため、プロパティイニシャライザーが非標準と見なされているためです。 しかし create-react-app
ジェネレーターはすでにステージ2を有効にしているので、近い将来、プロパティイニシャライザーがイベントハンドラーを定義するための事実上のものになる可能性が非常に高くなります。
プロパティイニシャライザーに慣れ、ハンドラーメソッドを定義するためにそれらを使い始めると、2つの注目すべき利点が得られます。
- 書き込みの定型文が少ない書き込む必要がない
bind
コンストラクターのステートメントはかなり甘いです。 これで、メソッドを定義するだけです-そしてそれだけです✨。 引数を渡す必要がある場合は、単一のクロージャーでラップし、そのハンドラー関数をで呼び出すことを忘れないでくださいrender
. 追加の利点として、イベントハンドラーを別の場所でリファクタリングする必要がある場合、カットペーストする場所は1つだけです。 - メモリ使用量の削減で矢印関数を使用
render
「設計による」レンダリングはコンポーネントのライフサイクル中に大量に発生するため、これは悪い考えです。 すべての矢印関数に新しいポインタを割り当てます。 の矢印機能を控えるrender
コンポーネントのメモリ使用量をダイエット中に維持していることを確認します。
このCodePenをチェックして、プロパティ初期化構文の動作を確認してください