Ich bin neu in der Verwendung von ES6-Klassen mit React. Vorher habe ich meine Methoden an das aktuelle Objekt gebunden (im ersten Beispiel gezeigt). Kann ich mit ES6 jedoch eine Klassenfunktion dauerhaft mit Pfeilen an eine Klasseninstanz binden? (Nützlich beim Übergeben als Rückruffunktion.) Ich erhalte Fehlermeldungen, wenn ich versuche, sie so wie möglich mit CoffeeScript zu verwenden:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
Wenn ich SomeClass.handleInputChange
beispielsweise an setTimeout
übergeben würde, würde dies auf die Klasseninstanz und nicht auf das window
-Objekt beschränkt sein.
Ihre Syntax ist etwas deaktiviert, es fehlt nur ein Gleichheitszeichen nach dem Eigenschaftsnamen.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
Dies ist eine experimentelle Funktion. Sie müssen experimentelle Funktionen in Babel aktivieren, damit dies kompiliert werden kann. Hier ist eine Demo mit aktiviertem Experiment.
Um experimentelle Funktionen in babel zu verwenden, können Sie das entsprechende Plugin von here installieren. Für diese spezielle Funktion benötigen Sie das transform-class-properties
Plugin :
{
"plugins": [
"transform-class-properties"
]
}
Lesen Sie mehr über den Vorschlag für Klassenfelder und statische Eigenschaften hier
Nein, wenn Sie gebundene, instanzspezifische Methoden erstellen möchten, müssen Sie dies im Konstruktor tun. Sie können jedoch Pfeilfunktionen dafür verwenden, anstatt .bind
für eine Prototypmethode zu verwenden:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
Es gibt einen Vorschlag , mit dem Sie möglicherweise die constructor()
weglassen und die Zuweisung direkt mit derselben Funktionalität in den Klassenbereich einfügen, aber ich würde nicht empfehlen, dies zu verwenden, da es äußerst experimentell ist.
Alternativ können Sie immer .bind
verwenden, wodurch Sie die Methode für den Prototyp deklarieren und dann an die Instanz im Konstruktor binden können. Dieser Ansatz ist flexibler, da er die Methode außerhalb der Klasse ändern kann.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
Ich weiß, dass diese Frage ausreichend beantwortet wurde, aber ich muss nur einen kleinen Beitrag leisten (für diejenigen, die die experimentelle Funktion nicht nutzen möchten). Wegen des Problems, mehrere Funktionsbindungen im Konstruktor binden zu müssen und es unordentlich aussehen zu lassen, habe ich eine Utility-Methode gefunden, die einmal im Konstruktor gebunden und aufgerufen wurde und alle erforderlichen Methodenbindungen automatisch für Sie ausführt.
Angenommen, ich habe diese Klasse mit dem Konstruktor:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
...//actual method declarations omitted
}
Es sieht unordentlich aus, nicht wahr? Jetzt habe ich diese Methode erstellt
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
Jetzt muss ich nur noch dieses Hilfsprogramm importieren und meinem Konstruktor einen Aufruf hinzufügen, und ich muss nicht mehr jede neue Methode im Konstruktor binden. Der neue Konstruktor sieht jetzt sauber aus:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
...
}
Sie verwenden die Pfeilfunktion und binden sie auch im Konstruktor ein. Sie müssen also nicht binden, wenn Sie Pfeilfunktionen verwenden
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
ODER Sie müssen eine Funktion nur im Konstruktor binden, wenn Sie eine normale Funktion wie unten verwenden
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Auch das direkte Binden einer Funktion in Rendering wird nicht empfohlen. Es sollte immer im Konstruktor sein