เหตุใด onClick ของฉันจึงถูกเรียกให้แสดงผล - React.js


111

ฉันมีส่วนประกอบที่ฉันสร้างขึ้น:

class Create extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    var playlistDOM = this.renderPlaylists(this.props.playlists);
    return (
      <div>
        {playlistDOM}
      </div>
    )
  }

  activatePlaylist(playlistId) {
    debugger;
  }

  renderPlaylists(playlists) {
    return playlists.map(playlist => {
      return <div key={playlist.playlist_id} onClick={this.activatePlaylist(playlist.playlist_id)}>{playlist.playlist_name}</div>
    });
  }
}

function mapStateToProps(state) {
  return {
    playlists: state.playlists
  }
}

export default connect(mapStateToProps)(Create);

เมื่อฉันเรียกrenderหน้าactivatePlaylistนี้สำหรับแต่ละหน้าplaylistในmapไฟล์. ถ้าฉันbind activatePlaylistชอบ:

activatePlaylist.bind(this, playlist.playlist_id)

ฉันยังสามารถใช้ฟังก์ชันที่ไม่ระบุตัวตน:

onClick={() => this.activatePlaylist(playlist.playlist_id)}

จากนั้นก็ใช้งานได้ตามที่คาดไว้ ทำไมสิ่งนี้ถึงเกิดขึ้น?

คำตอบ:


208

คุณจำเป็นต้องส่งผ่านไปยังonClick การอ้างอิงไปยังฟังก์ชั่นเมื่อคุณทำเช่นนี้activatePlaylist( .. )คุณเรียกฟังก์ชั่นและส่งผ่านไปยังค่าที่ส่งกลับจากonClick activatePlaylistคุณสามารถใช้หนึ่งในสามตัวเลือกเหล่านี้:

1 . โดยใช้.bind

activatePlaylist.bind(this, playlist.playlist_id)

2 . ใช้ฟังก์ชันลูกศร

onClick={ () => this.activatePlaylist(playlist.playlist_id) }

3 . หรือส่งคืนฟังก์ชันจากactivatePlaylist

activatePlaylist(playlistId) {
  return function () {
     // you code 
  }
}

ฉันจำไม่ได้ว่ามันใช้งานได้ในเวอร์ชันก่อนหน้าReactนี้ ฉันจำผิดหรือมีการapiเปลี่ยนแปลง?
jhamm

@jhamm คุณกำลังใช้คลาส ES6 และในกรณีนี้คุณควรผูกบริบทด้วยตนเอง
Oleksandr T.

@AlexanderT. มีสิ่งหนึ่งที่ฉันไม่เข้าใจ ถ้าคุณผูกบริบทด้วย.bindอย่างที่พูดในขั้นตอนที่ 1 จำเป็นต้องทำขั้นตอนที่ 2 หรือไม่? และถ้าเป็นเพราะเหตุใด เพราะฉันคิดว่าเมื่อคุณใช้ฟังก์ชันลูกศรบริบทคือบริบทที่เป็นที่กำหนดฟังก์ชัน แต่ถ้าเราแนบบริบทโดยใช้.bindบริบทจะแนบไปแล้วใช่ไหม
Rafa Romero

2
@ Rafa Romero มันเป็นเพียงสามทางเลือกที่แตกต่างกันคุณสามารถใช้หนึ่งในนั้น
Oleksandr T.

3
ขณะนี้มีส่วนหนึ่งในเว็บไซต์ React Docs อย่างเป็นทางการที่ตอบคำถามนี้ในเชิงลึก: reactjs.org/docs/faq-functions.html
zenoh

3

ฉันรู้ว่าโพสต์นี้มีอายุไม่กี่ปีแล้ว แต่เพียงเพื่ออ้างอิงบทช่วยสอน / เอกสาร React ล่าสุดเกี่ยวกับข้อผิดพลาดทั่วไปนี้ (ฉันทำไปแล้ว) จากhttps://reactjs.org/tutorial/tutorial.html :

บันทึก

เพื่อบันทึกการพิมพ์และหลีกเลี่ยงพฤติกรรมที่สับสนเราจะใช้ไวยากรณ์ของฟังก์ชันลูกศรสำหรับตัวจัดการเหตุการณ์ที่นี่และเพิ่มเติมด้านล่าง:

class Square extends React.Component {
 render() {
   return (
     <button className="square" onClick={() => alert('click')}>
       {this.props.value}
     </button>
   );
 }
}

สังเกตว่าเมื่อใช้ onClick = {() => alert ('click')} เราจะส่งผ่านฟังก์ชันเป็น onClick prop React จะเรียกใช้ฟังก์ชันนี้หลังจากคลิกเท่านั้น การลืม () => และการเขียน onClick = {alert ('click')} เป็นข้อผิดพลาดทั่วไปและจะเริ่มการแจ้งเตือนทุกครั้งที่คอมโพเนนต์แสดงผลซ้ำ


2

ลักษณะการทำงานนี้ได้รับการบันทึกไว้เมื่อ React ประกาศเปิดตัวคอมโพเนนต์ตามคลาส

https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html

การเชื่อมต่ออัตโนมัติ

React.createClass มีคุณสมบัติวิเศษในตัวที่ผูกวิธีการทั้งหมดไว้กับสิ่งนี้โดยอัตโนมัติสำหรับคุณ สิ่งนี้อาจสร้างความสับสนเล็กน้อยสำหรับนักพัฒนา JavaScript ที่ไม่คุ้นเคยกับฟีเจอร์นี้ในคลาสอื่นหรืออาจทำให้สับสนเมื่อย้ายจาก React ไปยังคลาสอื่น ๆ

ดังนั้นเราจึงตัดสินใจที่จะไม่นำสิ่งนี้มาใช้ในโมเดลคลาสของ React คุณยังคงสามารถผูกเมธอดไว้ล่วงหน้าอย่างชัดเจนในตัวสร้างของคุณได้หากต้องการ


1

วิธีที่คุณผ่านเมธอดthis.activatePlaylist(playlist.playlist_id)จะเรียกใช้เมธอดทันที คุณควรส่งต่อการอ้างอิงของวิธีการไปยังonClickเหตุการณ์ ปฏิบัติตามหนึ่งในการใช้งานที่กล่าวถึงด้านล่างเพื่อแก้ไขปัญหาของคุณ

1.
onClick={this.activatePlaylist.bind(this,playlist.playlist_id)}

คุณสมบัติการผูกที่นี่ใช้เพื่อสร้างการอ้างอิงของthis.activatePlaylistวิธีการโดยส่งผ่านthisบริบทและอาร์กิวเมนต์playlist.playlist_id

2.
onClick={ (event) => { this.activatePlaylist.(playlist.playlist_id)}}

สิ่งนี้จะแนบฟังก์ชันเข้ากับเหตุการณ์ onClick ซึ่งจะเรียกใช้เมื่อผู้ใช้คลิกเท่านั้น เมื่อรหัสนี้ออกจากthis.activatePlaylistเมธอดจะถูกเรียกใช้

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