it-swarm.com.de

Wie verwende ich Pfeilfunktionen (öffentliche Klassenfelder) als Klassenmethoden?

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.

150
Ben

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


180
Guy

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);
  }
}
54
Bergi

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);
    }
    ...
}

2
kennasoft

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

0
Hemadri Dasari