วิธีการใช้ฟังก์ชั่นลูกศร (เขตข้อมูลชั้นสาธารณะ) เป็นวิธีการเรียน?


181

ฉันยังใหม่กับการใช้คลาส ES6 กับ React ก่อนหน้านี้ฉันผูกเมธอดของฉันกับวัตถุปัจจุบัน (แสดงในตัวอย่างแรก) แต่ ES6 อนุญาตให้ฉันผูกฟังก์ชันคลาสกับอินสแตนซ์ของคลาสด้วยลูกศรอย่างถาวรหรือไม่ (มีประโยชน์เมื่อผ่านเป็นฟังก์ชั่นการโทรกลับ) ฉันได้รับข้อผิดพลาดเมื่อฉันพยายามใช้พวกเขาเท่าที่คุณสามารถทำได้ด้วย 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);
  }

ดังนั้นถ้าฉันจะส่งผ่านSomeClass.handleInputChangeไปเช่นsetTimeoutมันจะถูกกำหนดขอบเขตให้กับอินสแตนซ์ของชั้นเรียนไม่ใช่windowวัตถุ


1
ฉันสนใจที่จะรู้คำตอบเดียวกันกับTypeScript
Mars Robertson

โซลูชันของ TypeScript เหมือนกับข้อเสนอ ES7 (ดูคำตอบที่ยอมรับ ) สิ่งนี้ได้รับการสนับสนุนโดย TypeScript
Philip Bulley


1
คุณควรหลีกเลี่ยงการใช้ฟังก์ชั่นลูกศรในชั้นเรียนเนื่องจากมันจะไม่เป็นส่วนหนึ่งของต้นแบบและไม่ได้แชร์โดยทุกครั้ง มันเหมือนกับการให้สำเนาฟังก์ชั่นเดียวกันกับทุก ๆ อินสแตนซ์
Sourabh Ranka

คำตอบ:


205

ไวยากรณ์ของคุณปิดอยู่เล็กน้อยเพียงแค่ไม่มีเครื่องหมายเท่ากับหลังจากชื่อคุณสมบัติ

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

นี่คือคุณลักษณะทดลอง คุณจะต้องเปิดใช้งานฟีเจอร์การทดลองใน Babel เพื่อให้สามารถรวบรวมได้ นี่คือตัวอย่างที่เปิดใช้งานการทดลอง

หากต้องการใช้คุณลักษณะการทดลองใน Babel คุณสามารถติดตั้งปลั๊กอินที่เกี่ยวข้องจากที่นี่ สำหรับคุณสมบัติเฉพาะนี้คุณต้องมีtransform-class-propertiesปลั๊กอิน :

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

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับข้อเสนอสำหรับคลาสฟิลด์และคุณสมบัติคงที่ได้ที่นี่



4
(แม้ว่าฉันจะรู้ว่าทำงานนอกห้องเรียน ES6) ซึ่งดูเหมือนจะไม่เหมาะกับฉัน แต่ Babel ก็โยนลูกศรโทเค็นที่ไม่คาดคิดในครั้งแรก=ที่handleInputChange =
เบ็

40
คุณควรให้คำอธิบายบางอย่างเช่นนี่เป็นคุณลักษณะทดลองสำหรับข้อเสนอ ES7
เฟลิกซ์คลิง

1
ร่างข้อกำหนดปัจจุบันมีการเปลี่ยนแปลงในเดือนกันยายนดังนั้นคุณไม่ควรใช้มันสำหรับการปฏิเสธอัตโนมัติตามที่ Babel เสนอ
chico

1
สำหรับ Babel 6.3.13 คุณต้องเปิดใช้งาน presets 'es2015' และ 'stage-1' เพื่อรวบรวมสิ่งนี้
Andrew

12
มันใช้งานได้ แต่มีการเพิ่มวิธีการไปยังอินสแตนซ์ใน Constructor แทนที่จะถูกเพิ่มเข้ากับต้นแบบและมีความแตกต่างใหญ่
lib3d

61

ไม่ถ้าคุณต้องการสร้างวิธีการอินสแตนซ์เฉพาะคุณจะต้องทำเช่นนั้นใน Constructor อย่างไรก็ตามคุณสามารถใช้ฟังก์ชั่นลูกศรแทนการใช้.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);
  }
}

4

ฉันรู้ว่าคำถามนี้ได้รับคำตอบอย่างเพียงพอ แต่ฉันมีเพียงเล็กน้อยที่จะทำ (สำหรับผู้ที่ไม่ต้องการใช้คุณลักษณะการทดลอง) เนื่องจากปัญหาของการผูกหลายฟังก์ชันผูกในตัวสร้างและทำให้ดูยุ่งเหยิงฉันมาด้วยวิธีอรรถประโยชน์ที่ครั้งหนึ่งเคยถูกผูกไว้และเรียกในตัวสร้างทำให้ทุกวิธีที่จำเป็นสำหรับคุณผูกโดยอัตโนมัติ

สมมติว่าฉันมีคลาสนี้กับตัวสร้าง:

//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/…
Michael Freidgeim

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

ไม่แนะนำให้ผูกฟังก์ชันในการเรนเดอร์โดยตรง มันควรจะอยู่ในตัวสร้าง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.