web-dev-qa-db-fra.com

Comment utiliser les fonctions de flèche (champs de classe publics) comme méthodes de classe?

J'utilise pour la première fois les classes ES6 avec React; auparavant, je liais mes méthodes à l'objet actuel (présenté dans le premier exemple), mais ES6 me permet-il de lier de manière permanente une fonction de classe à une instance de classe avec des flèches? (Utile pour passer en tant que fonction de rappel.) J'obtiens des erreurs lorsque j'essaie de les utiliser comme vous pouvez le faire avec CoffeeScript:

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

Ainsi, si je transmettais SomeClass.handleInputChange à, par exemple, setTimeout, il serait étendu à l'instance de la classe et non à l'objet window.

150
Ben

Votre syntaxe est légèrement incorrecte, il manque juste un signe égal après le nom de la propriété.

class SomeClass extends React.Component {
  handleInputChange = (val) => {
    console.log('selectionMade: ', val);
  }
}

Ceci est une fonctionnalité expérimentale. Pour que cela soit compilé, vous devez activer les fonctionnalités expérimentales dans Babel. Here est une démo avec expérimental activé. 

Pour utiliser les fonctionnalités expérimentales de babel, vous pouvez installer le plug-in correspondant à partir de ici . Pour cette fonctionnalité spécifique, vous avez besoin du plugin transform-class-properties :

{
  "plugins": [
    "transform-class-properties"
  ]
}

Vous pouvez en savoir plus sur la proposition relative aux champs de classe et aux propriétés statiques ici


180
Guy

Non, si vous voulez créer des méthodes liées, spécifiques à une instance, vous devrez le faire dans le constructeur. Cependant, vous pouvez utiliser des fonctions de flèche pour cela au lieu d'utiliser .bind sur une méthode prototype:

class SomeClass extends React.Component {
  constructor() {
    super();
    this.handleInputChange = (val) => {
      console.log('selectionMade: ', val, this);
    };
    …
  }
}

Il y a une proposition qui pourrait vous permettre d'omettre la constructor() et de placer directement l'affectation dans la portée de la classe avec la même fonctionnalité, mais je ne recommanderais pas de l'utiliser car elle est très expérimentale.

Sinon, vous pouvez toujours utiliser .bind , ce qui vous permet de déclarer la méthode sur le prototype, puis de la lier à l'instance du constructeur. Cette approche offre une plus grande flexibilité car elle permet de modifier la méthode depuis l’extérieur de votre classe.

class SomeClass extends React.Component {
  constructor() {
    super();
    this.handleInputChange = this.handleInputChange.bind(this);
    …
  }
  handleInputChange(val) {
    console.log('selectionMade: ', val, this);
  }
}
54
Bergi

Je sais que cette question a reçu une réponse suffisante, mais j’ai juste une petite contribution à faire (pour ceux qui ne veulent pas utiliser la fonctionnalité expérimentale). En raison du problème de lier plusieurs liaisons de fonctions dans le constructeur et de lui donner un aspect confus, j'ai proposé une méthode utilitaire qui, une fois liée et appelée dans le constructeur, effectue automatiquement toutes les liaisons de méthodes nécessaires.

Supposons que j'ai cette classe avec le constructeur:

//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
  
}

Cela semble compliqué, n'est-ce pas? Maintenant, j'ai créé cette méthode utilitaire

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

Tout ce que j'ai maintenant besoin de faire est d'importer cet utilitaire et d'ajouter un appel à mon constructeur, et je n'ai plus besoin de lier chaque nouvelle méthode dans le constructeur .

//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

Vous utilisez la fonction de flèche et la liez également dans le constructeur. Donc, vous n'avez pas besoin de faire la liaison lorsque vous utilisez des fonctions de flèche 

class SomeClass extends React.Component {
  handleInputChange = (val) => {
    console.log('selectionMade: ', val);
  }
}

OU vous devez lier une fonction uniquement dans le constructeur lorsque vous utilisez une fonction normale comme ci-dessous

class SomeClass extends React.Component {
   constructor(props){
      super(props);
      this.handleInputChange = this.handleInputChange.bind(this);
   }

  handleInputChange(val){
    console.log('selectionMade: ', val);
  }
}

De plus, lier une fonction directement dans le rendu n'est pas recommandé. Il devrait toujours être en constructeur

0
Hemadri Dasari