最近、React.jsをいじり始めましたが、とても気に入っています。私は通常のES5から始めたので、物事を理解するために、ドキュメントはすべてES5で書かれています...
しかし今、私はES6を試してみたかったのです。なぜなら、それは光沢があり、新しく、いくつかのことを単純化するように思われるからです。気になっているのは、コンポーネントクラスに追加したメソッドごとに、「this」にバインドする必要があることです。そうしないと機能しません。したがって、私のコンストラクタは次のようになります。
constructor(props) {
super(props);
this.state = { ...some initial state... }
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
}
クラスにさらにメソッドを追加すると、これはさらに大きくて見苦しい混乱になります。
私の質問は、これを回避する方法はありますか、少なくともそれをより簡単に、短く、andくしませんか? React ES6で試したかった主な理由の1つは、コードをより簡潔にすることでしたが、これは反対です。提案や入力をいただければ幸いです。
class fields を使用して、コンストラクターの外側でバインディングを行うことができます。次のようになります。
class Foo extends React.Component {
handleBar = () => {
console.log('neat');
};
handleFoo = () => {
console.log('cool');
};
render() {
return (
<div
onClick={this.handleBar}
onMouseOver={this.handleFoo}
/>
);
}
}
クラスフィールドは クラスプロパティtransform を介して実験的にサポートされていますが、 ステージ3ドラフト (まだバベルプリセットではない)であるため、「実験的」です。
ただし、ES7まで、またはBabelで機能を有効にするまで、手動でバインドを行う必要があります。 React on ES6 + に関するBabelのブログ投稿で、このトピックについて簡単に説明しています。
別の方法は、デコレータを使用することです。プロトタイプでゲッターを宣言し、インスタンスへの最初のアクセスで、その関数のバインドされたバージョンで独自のプロパティを定義します。
しかし、キャッチがあります!開発では、プロパティは置き換えられず、すべてのアクセスでバインドされます。 これは、react-hot-loaderを壊さないことを意味します。少なくとも私にとって、それは非常に重要です。
これを提供するライブラリ class-bind を作成しました。
import {bound} from 'class-bind';
class App {
constructor(){
this.foo = 'bar';
}
@bound
returnsFoo(){
return this.foo;
}
render(){
var returnsFoo = this.returnsFoo;
return (
<div>
{returnsFoo()} === 'bar'
</div>
);
}
}
あなたにとってデコレータは不安定すぎますか?すべてまたはいくつかのものを同じ利点でバインドできます。
import {bind, bindAll} from 'class-bind';
bind(App.prototype, 'returnsFoo');
// or
bindAll(App.prototype);
バインドを回避する1つのアイデア
class MyComp extends Component {
render() {
return <button onClick={e => this.handleClick(e)}>Do Things</button>
}
}
免責事項:テストされていないため、複数の引数を簡単に処理できません(この場合、イベント(e)が1つあります)。
また、これはおそらく価値のあるこの記事によると、おそらくnotの例です。
すべての「バインド」を整理するメソッドを作成しました。
class MyClass {
constructor() {
this.bindMethods([
'updateLocationFields',
'render',
'loadCities',
]);
}
bindMethods(methods) {
methods.forEach((item) => {
this[item] = this[item].bind(this);
});
}
...
}
ソラレンの提案は素晴らしいですが、別の方法が必要な場合は次のとおりです。
class AppCtrlRender extends Component {
binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }
render() {
var isMobile = this.state.appData.isMobile;
var messages = this.state.appData.messages;
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 1.3 Slider
<br/><br/>
<div className='FlexBoxWrap'>
<Slider isMobile={isMobile}/>
<JList data={messages}/>
</div>
</div>
);
}
}
var getAppState = function() {
return {
appData: AppStore.getAppData()
};
};
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getAppState();
this.binder('appStoreDidChange');
}
componentDidMount() {
var navPlatform = window.navigator.platform;
Actions.setWindowDefaults(navPlatform);
}
componentWillMount() { AppStore.onAny(this.appStoreDidChange); }
componentWillUnmount() { AppStore.offAny(this.appStoreDidChange); }
appStoreDidChange() { this.setState(getAppState()); }
}
This.binder( 'method1'、 'method2'、...)に任意の数のメソッドを追加できます
私は実際に、子に親コンテキストを渡すことでOOP継承を模倣することを好みます。
class Parent extends Component {
state = {happy: false}
changeState(happy) {
this.setState({happy})
}
render() {
return (
<Child parent={this} >
)
}
}
class Child extends Component {
//...
this.props.parent.changeState(true)
}
0.02ドル、ジョン
_stage-0
_を使用する場合、関数バインディング構文があります。
_class MyComp extends Component {
handleClick() { console.log('doing things') }
render() {
return <button onClick={::this.handleClick}>Do Things</button>
}
}
_
これはthis.handleClick.call(this)
に分解されます。これは一般に十分なパフォーマンスがあると思います。
ヘルパー関数doBinding(this)
を使用します。これは各コンストラクターで呼び出します。この例では、_handleChange1()
と_handleChange2()
をバインドします。
_class NameForm extends React.Component {
constructor(props) {
super(props);
doBinding(this);
this.state = {value1: "", value2: ""};
}
_handleChange1(event) {
this.setState({value1: event.target.value});
}
_handleChange2(event) {
this.setState({value2: event.target.value});
}
render() {
...
}
}
_
この方法は、Babelを使用していない場合でも機能します。
私のハンドラーメソッドはすべて__
_(プライベートであることを示す規則)で始まります。したがって、doBinding()
は__
_を探します。この規則を使用しない場合は、if (key.startsWith("_"))
を削除できます。
_function doBinding(obj) {
const proto = Object.getPrototypeOf(obj);
for (const key of Object.getOwnPropertyNames(proto)) {
if (key.startsWith("_")) {
obj[key] = obj[key].bind(obj);
}
}
}
_