क्लास के तरीकों के रूप में एरो फ़ंक्शंस (पब्लिक क्लास फील्ड्स) का उपयोग कैसे करें?


181

मैं रिएक्ट के साथ ईएस 6 कक्षाओं का उपयोग करने के लिए नया हूं, पहले मैं अपने तरीकों को वर्तमान वस्तु (पहले उदाहरण में दिखाता हूं) के लिए बाध्य कर रहा हूं, लेकिन क्या ईएस 6 मुझे तीर के साथ एक वर्ग समारोह को स्थायी रूप से एक वर्ग समारोह में बाँधने की अनुमति देता है? (कॉलबैक फ़ंक्शन के रूप में गुजरते समय उपयोगी।) जब मुझे कॉफ़ीस्क्रिप्ट के साथ उपयोग करने की कोशिश की जाती है, तो मुझे त्रुटियाँ मिलती हैं:

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

SomeClass.handleInputChangeउदाहरण के लिए setTimeout, अगर मुझे पास करना होता है, तो यह क्लास के उदाहरण के लिए स्कोप किया जाएगा, न कि windowऑब्जेक्ट को।


1
मैं टाइपस्क्रिप्ट
मार्स रॉबर्टसन

टाइपस्क्रिप्ट का समाधान ES7 प्रस्ताव ( स्वीकृत उत्तर देखें ) के समान है। यह मूलरूप से टाइपस्क्रिप्ट द्वारा समर्थित है।
फिलिप बुल्ले

2
सभी के लिए जो यहाँ समाप्त होते हैं, विषय पर एक दिलचस्प पढ़ा "क्लास के गुणों में तीर फ़ंक्शन उतना महान नहीं हो सकता जितना हम सोचते हैं"
विल्ट

1
आपको कक्षा में तीर के कार्यों का उपयोग करने से बचना चाहिए क्योंकि वे प्रोटोटाइप का हिस्सा नहीं होंगे और इस प्रकार हर उदाहरण द्वारा साझा नहीं किया जाएगा। यह प्रत्येक उदाहरण के लिए फ़ंक्शन की समान प्रतिलिपि देने के समान है।
सौरभ रांका

जवाबों:


205

आपका सिंटैक्स थोड़ा बंद है, बस संपत्ति के नाम के बराबर चिह्न गायब है।

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

यह एक प्रायोगिक विशेषता है। आपको इसे संकलित करने के लिए बैबिल में प्रयोगात्मक सुविधाओं को सक्षम करने की आवश्यकता होगी। यहाँ प्रयोगात्मक सक्षम के साथ एक डेमो है।

बेबल में प्रायोगिक सुविधाओं का उपयोग करने के लिए आप यहां से संबंधित प्लगइन स्थापित कर सकते हैं । इस विशिष्ट सुविधा के लिए, आपको transform-class-propertiesप्लगइन की आवश्यकता है :

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

आप यहां क्लास फील्ड्स और स्टेटिक प्रॉपर्टीज के प्रस्ताव के बारे में अधिक पढ़ सकते हैं



4
यह मेरे लिए काम करने के लिए प्रकट नहीं होता है (हालांकि मैं एक ES6 वर्ग के बाहर है कि काम करता है पता है), कोलाहल पहली बार में एक अप्रत्याशित टोकन तीर फेंकता =परhandleInputChange =
बेन

40
आपको कुछ स्पष्टीकरण देना चाहिए, जैसे कि यह ES7 प्रस्ताव के लिए एक प्रयोगात्मक विशेषता है।
फेलिक्स क्लिंग

1
वर्तमान विनिर्देश ड्राफ्ट को सितंबर में बदल दिया गया था, इसलिए आपको इसे ऑटोबिंड के लिए उपयोग नहीं करना चाहिए क्योंकि बैबल का प्रस्ताव है।
चिको

1
बाबेल 6.3.13 के लिए आपको इसे संकलित करने के लिए 'es2015' और 'स्टेज -1' को प्रीसेट करने की आवश्यकता है
एंड्रयू

12
यह काम करता है, लेकिन विधि को प्रोटोटाइप में जोड़े जाने के बजाय उदाहरण में जोड़ा जाता है और इसका बड़ा अंतर है।
lib3d

61

नहीं, यदि आप बाध्य, उदाहरण-विशिष्ट तरीके बनाना चाहते हैं, तो आपको निर्माणकर्ता में ऐसा करना होगा। हालाँकि, आप इसके लिए तीर फ़ंक्शंस का उपयोग कर सकते हैं, बजाय .bindएक प्रोटोटाइप विधि पर उपयोग करने के:

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

एक प्रस्ताव है जो आपको constructor()उसी कार्यशीलता के साथ वर्ग के दायरे में कार्यभार छोड़ने और सीधे कार्य करने की अनुमति दे सकता है , लेकिन मैं इसका उपयोग करने की अनुशंसा नहीं करूंगा क्योंकि यह अत्यधिक प्रयोगात्मक है।

वैकल्पिक रूप से, आप हमेशा उपयोग कर सकते हैं .bind, जो आपको प्रोटोटाइप पर विधि की घोषणा करने की अनुमति देता है और फिर इसे कंस्ट्रक्टर में उदाहरण के लिए बाँध देता है। इस दृष्टिकोण में अधिक लचीलापन है क्योंकि यह आपकी कक्षा के बाहर से विधि को संशोधित करने की अनुमति देता है।

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

3

आप एरो फंक्शन का उपयोग कर रहे हैं और इसे कंस्ट्रक्टर में बाँध भी रहे हैं। तो जब आप एरो फ़ंक्शंस का उपयोग करते हैं तो आपको बाइंडिंग करने की आवश्यकता नहीं है

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

या आपको किसी फ़ंक्शन को केवल कंस्ट्रक्टर में बाँधने की आवश्यकता होती है जब आप नीचे दिए गए सामान्य फ़ंक्शन का उपयोग करते हैं

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

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

सीधे रेंडर में एक फ़ंक्शन को बांधना अनुशंसित नहीं है। यह हमेशा कंस्ट्रक्टर में होना चाहिए


3

मुझे पता है कि इस सवाल का पर्याप्त रूप से उत्तर दिया गया है, लेकिन मेरा सिर्फ एक छोटा सा योगदान है (उन लोगों के लिए जो प्रयोगात्मक सुविधा का उपयोग नहीं करना चाहते हैं)। कई फ़ंक्शन को बाइंड करने की समस्या के कारण कंस्ट्रक्टर में बांधता है और इसे गन्दा दिखता है, मैं एक उपयोगिता विधि के साथ आया था जो एक बार बाध्य हो जाने और कंस्ट्रक्टर में बुलाया जाता है, आपके लिए सभी आवश्यक विधि बाइंडिंग स्वचालित रूप से करता है।

मान लें कि मेरे पास कंस्ट्रक्टर के साथ यह वर्ग है:

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

यह गन्दा लगता है, है ना? अब मैंने यह उपयोगिता विधि बनाई

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

मुझे अब केवल उस उपयोगिता को आयात करने की आवश्यकता है, और मेरे निर्माता को एक कॉल जोड़ें, और मुझे अब निर्माणकर्ता में प्रत्येक नई विधि को बांधने की आवश्यकता नहीं है। नया कंस्ट्रक्टर अब साफ दिखता है, जैसे:

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


आपका समाधान अच्छा है, हालांकि यह सभी जीवन चक्र विधियों को कवर नहीं करता है जब तक कि आप उन्हें दूसरे तर्क में घोषित नहीं करते हैं। उदाहरण के लिए: shouldComponentUpdateऔरgetSnapshotBeforeUpdate
WebDeg Brian

आपका विचार ऑटोबाइंडिंग के समान है, जिसमें ध्यान देने योग्य प्रदर्शन में गिरावट है। आपको केवल उन कार्यों को बांधने की आवश्यकता है जिन्हें आप पास करते हैं। देखें medium.com/@charpeni/...
माइकल Freidgeim
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.