¿Cómo usar las funciones de flecha (campos de clase públicos) como métodos de clase?


Soy nuevo en el uso de clases ES6 con React, anteriormente he estado vinculando mis métodos al objeto actual (mostrar en el primer ejemplo), pero ES6 me permite vincular permanentemente una función de clase a una instancia de clase con flechas? (Útil cuando se pasa como una función de devolución de llamada.) Tengo errores cuando trato de usarlos como se puede con 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);
  }

De modo que si tuviera que pasar SomeClass.handleInputChange a, por ejemplo setTimeout, sería un ámbito a la instancia de la clase, y no al objeto window.

Author: Felix Kling, 2015-07-12

4 answers

Su sintaxis está ligeramente apagada, solo le falta un signo igual después del nombre de la propiedad.

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

Esta es una característica experimental. Necesitará habilitar características experimentales en Babel para que esto se compile. Aquí es una demo con experimental activado.

Para usar funciones experimentales en babel puede instalar el plugin correspondiente desde aquí. Para esta característica específica, necesita la transform-class-properties plugin :

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

Puedes leer más sobre la propuesta para Campos de Clase y Propiedades estáticas aquí


 171
Author: Guy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-10 07:45:43

No, si desea crear métodos específicos de instancia enlazados, tendrá que hacerlo en el constructor. Sin embargo, puede usar funciones de flecha para eso, en lugar de usar .bind en un método prototipo:

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

Hay una propuesta que podría permitir omitir el constructor() y poner directamente la asignación en el ámbito de la clase con la misma funcionalidad, pero no recomendaría usar eso ya que es altamente experimental.

Alternativamente, siempre puede usar .bind, que le permite declarar el método en el prototipo y luego vincularlo a la instancia en el constructor. Este enfoque tiene mayor flexibilidad, ya que permite modificar el método desde el exterior de su clase.

class SomeClass extends React.Component {
  constructor() {
    super();
    this.handleInputChange = this.handleInputChange.bind(this);
    …
  }
  handleInputChange(val) {
    console.log('selectionMade: ', val, this);
  }
}
 52
Author: Bergi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-19 01:05:58

Sé que esta pregunta ha sido suficientemente respondida, pero solo tengo una pequeña contribución que hacer (para aquellos que no quieren usar la función experimental). Debido al problema de tener que enlazar múltiples enlaces de funciones en el constructor y hacer que se vea desordenado, se me ocurrió un método de utilidad que una vez enlazado y llamado en el constructor, hace todos los enlaces de métodos necesarios para usted automáticamente.

Asumir que tengo esta clase con el constructor:

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

Se ve desordenado, ¿no? Ahora he creado este método de utilidad

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

Todo lo que tengo que hacer ahora es importar esa utilidad, y agregar una llamada a mi constructor, y ya no necesito enlazar cada nuevo método en el constructor. Nuevo constructor ahora se ve limpio, así:

//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
Author: kennasoft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-17 17:00:03

Está utilizando la función arrow y también la enlaza en constructor. Por lo tanto, no es necesario hacer enlaces cuando se utilizan las funciones de flecha

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

O necesita enlazar una función solo en constructor cuando usa una función normal como la siguiente

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

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

Tampoco se recomienda enlazar una función directamente en render. Siempre debe estar en constructor

 0
Author: Think-Twice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 13:17:23