Ok yöntemleri (genel sınıf alanları) sınıf yöntemi olarak nasıl kullanılır?


181

React ile ES6 sınıflarını kullanmak için yeni, daha önce yöntemlerimi geçerli nesneye bağladım (ilk örnekte göster), ama ES6 kalıcı olarak bir sınıf işlevini oklarla bir sınıf örneği bağlamak için izin veriyor mu? (Geri arama işlevi olarak geçerken kullanışlıdır.) CoffeeScript ile bunları mümkün olduğunca kullanmaya çalıştığımda hata alıyorum:

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

Böylece, SomeClass.handleInputChangeörneğin geçecek olsaydım setTimeout, windownesneye değil, sınıf örneğine dahil edilirdi .


1
Ben aynı cevabı bilmek istiyorum TypeScript
Mars Robertson

TypeScript'in çözümü ES7 teklifiyle aynıdır ( kabul edilen cevaba bakınız ). Bu, yerel olarak TypeScript tarafından desteklenir.
Philip Bulley


1
Prototipin bir parçası olmayacağı ve dolayısıyla her örnek tarafından paylaşılmadığından, ok işlevlerini sınıfta kullanmaktan kaçınmalısınız. Her örneğe aynı işlev kopyasını vermekle aynıdır.
Sourabh Ranka

Yanıtlar:


205

Sözdiziminiz biraz kapalı, özellik adından sonra eşittir işareti eksik.

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

Bu deneysel bir özelliktir. Bunu derlemek için Babel'de deneysel özellikleri etkinleştirmeniz gerekecek. İşte deneysel özellikli bir demo.

Eğer alakalı eklentiyi kurabilirsiniz babel deneysel özelliklerini kullanmak için buraya . Bu özel özellik için transform-class-propertieseklentiye ihtiyacınız var :

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

Sınıf Alanları ve Statik Özellikler için teklif hakkında daha fazla bilgiyi buradan edinebilirsiniz.



4
Benim için işin görünmüyor (Ben dışarıda bir ES6 sınıfının o çalıştığını biliyorum rağmen), Babil ilk başta beklenmedik bir belirteç ok atar =athandleInputChange =
Ben

40
Biraz açıklama yapmalısınız, örneğin bunun bir ES7 teklifi için deneysel bir özellik olduğu.
Felix Kling

1
mevcut şartname taslağı Eylül ayında değiştirildi, bu yüzden Babel'in önerdiği gibi otoyol için kullanmamalısınız.
chico

1
Babel 6.3.13 için bunu derlemek için 'es2015' ve 'stage-1' ön ayarlarının etkinleştirilmesi gerekir
Andrew

12
Çalışır, ancak yöntem prototipe eklenmek yerine yapıcıdaki örneğe eklenir ve bu büyük bir farktır.
lib3d

61

Hayır, bağlı, örneğe özgü yöntemler oluşturmak istiyorsanız bunu yapıcıda yapmanız gerekir. Ancak, .bindbir prototip yönteminde kullanmak yerine bunun için ok işlevlerini kullanabilirsiniz :

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

Ödevi atlamanıza ve doğrudan aynı işlevselliğe sahip sınıf kapsamına koymanıza izin verebilecek bir teklif var constructor(), ancak bunu son derece deneysel olduğu için kullanmanızı önermem.

Alternatif olarak, .bindyöntemi prototipte bildirmenize ve ardından yapıcıdaki örneğe bağlamanıza izin veren her zaman kullanabilirsiniz . Bu yaklaşım, yöntemin sınıfınızın dışından değiştirilmesine izin verdiği için daha fazla esnekliğe sahiptir.

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

4

Bu sorunun yeterince cevaplandığını biliyorum, ama yapmak için sadece küçük bir katkım var (deneysel özelliği kullanmak istemeyenler için). Yapıcıda birden çok işlev bağlaması ve dağınık görünmesini sağlama sorunu nedeniyle, bir kez yapıcıya bağlanan ve çağrılan, sizin için tüm gerekli yöntem bağlarını otomatik olarak yapan bir yardımcı program buldum.

Yapıcı ile bu sınıf var varsayalım:

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

Dağınık görünüyor, değil mi? Şimdi bu yardımcı yöntemi yarattım

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

Şimdi tek yapmam gereken bu yardımcı programı içe aktarmak ve yapıcıma bir çağrı eklemek ve artık yapıcıdaki her yeni yöntemi bağlamak zorunda değilim. Yeni kurucu şimdi şu şekilde temiz görünüyor:

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


Çözümünüz güzel, ancak ikinci argümanda beyan etmedikçe tüm yaşam döngüsü yöntemlerini kapsamıyor. Örneğin: shouldComponentUpdatevegetSnapshotBeforeUpdate
WebDeg Brian

Fikriniz, belirgin bir performans düşüşü olan otomatik taşıtlamaya benzer. Yalnızca geçtiğiniz işlevleri bağlamanız gerekir. Bkz. Medium.com/@charpeni/…
Michael Freidgeim

3

Ok işlevini kullanıyorsunuz ve aynı zamanda yapıcıda da bağlıyorsunuz. Bu nedenle, ok işlevlerini kullanırken ciltleme yapmanıza gerek yoktur

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

VEYA aşağıdaki gibi normal işlevi kullandığınızda bir işlevi yalnızca yapıcıda bağlamanız gerekir

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

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

Ayrıca bir işlevin doğrudan render içinde bağlanması önerilmez. Her zaman yapıcı içinde olmalıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.