Je suis nouveau dans l'utilisation des classes ES6 avec React, auparavant j'avais lié mes méthodes à l'objet actuel (voir 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 lors du passage en tant que fonction de rappel.) J'obtiens des erreurs lorsque j'essaye de les utiliser comme vous le pouvez 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 devais passer SomeClass.handleInputChange
à, par exemple setTimeout
, il serait limité à l'instance de classe, et non à l' window
objet.
Réponses:
Votre syntaxe est légèrement décalée, 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. Vous devrez activer les fonctionnalités expérimentales de Babel pour que cela soit compilé. Voici une démo avec expérimental activé.
Pour utiliser les fonctionnalités expérimentales de babel, vous pouvez installer le plugin approprié à partir d' ici . Pour cette fonctionnalité spécifique, vous avez besoin du
transform-class-properties
plugin :{ "plugins": [ "transform-class-properties" ] }
Vous pouvez en savoir plus sur la proposition de champs de classe et de propriétés statiques ici
la source
=
àhandleInputChange =
Non, si vous souhaitez créer des méthodes liées et spécifiques à une instance, vous devrez le faire dans le constructeur. Cependant, vous pouvez utiliser les fonctions fléchées 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 existe une proposition qui pourrait vous permettre d'omettre
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 hautement expérimentale.Sinon, vous pouvez toujours utiliser
.bind
, qui vous permet de déclarer la méthode sur le prototype, puis de la lier à l'instance dans le constructeur. Cette approche a une plus grande flexibilité car elle permet de modifier la méthode de 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); } }
la source
Je sais que cette question a reçu une réponse suffisante, mais j'ai juste une petite contribution à apporter (pour ceux qui ne veulent pas utiliser la fonction expérimentale). En raison du problème de devoir lier plusieurs liaisons de fonction dans le constructeur et de le rendre désordonné, 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éthode nécessaires pour vous.
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 }
Ça a l'air désordonné, 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 à faire maintenant 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. Le nouveau constructeur semble maintenant propre, comme ceci:
//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); } // ... }
la source
shouldComponentUpdate
etgetSnapshotBeforeUpdate
Vous utilisez la fonction de flèche et la liez également dans le constructeur. Vous n'avez donc pas besoin de faire de liaison lorsque vous utilisez les fonctions fléchées
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); } }
Il est également déconseillé de lier une fonction directement dans le rendu. Il devrait toujours être dans le constructeur
la source