Tại sao onClick của tôi được gọi khi kết xuất? - React.js


100

Tôi có một thành phần mà tôi đã tạo:

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

Khi tôi rendertrang này, activatePlaylistđược gọi cho mỗi trang playlistcủa tôi map. Nếu tôi bind activatePlaylistthích:

activatePlaylist.bind(this, playlist.playlist_id)

Tôi cũng có thể sử dụng một chức năng ẩn danh:

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

sau đó nó hoạt động như mong đợi. Lý do tại sao điều này xảy ra?

Câu trả lời:


191

Bạn cần truyền đến onClick tham chiếu đến hàm, khi bạn làm như vậy, activatePlaylist( .. )bạn gọi hàm và chuyển đến onClickgiá trị được trả về từ đó activatePlaylist. Bạn có thể sử dụng một trong ba tùy chọn sau:

1 . sử dụng.bind

activatePlaylist.bind(this, playlist.playlist_id)

2 . sử dụng chức năng mũi tên

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

3 . hoặc trả về chức năng từactivatePlaylist

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

Tôi không nhớ nó làm việc trong các phiên bản trước của Reactcách này. Tôi đang nhớ sai hay đã apithay đổi?
jhamm

@jhamm Bạn đang sử dụng các lớp ES6 và trong trường hợp này, bạn nên ràng buộc ngữ cảnh theo cách thủ công.
Alexander T.

@AlexanderT. có một điều mà tôi không hiểu. Nếu bạn ràng buộc ngữ cảnh với .bind, như bạn đã nói ở bước 1, bạn có cần thực hiện bước 2 không? và nếu có, tại sao? Bởi vì tôi nghĩ rằng khi bạn sử dụng hàm arrow, ngữ cảnh chính là nơi hàm được định nghĩa, nhưng nếu chúng ta gắn ngữ cảnh bằng cách sử dụng .bindthì ngữ cảnh đã được đính kèm rồi phải không?
Rafa Romero

2
@Rafa Romero nó chỉ là ba tùy chọn khác nhau, bạn có thể sử dụng một trong số họ
Alexander T.

2
Hiện đã có một phần trên trang web chính thức của Tài liệu React đã trả lời đầy đủ câu hỏi này: reactjs.org/docs/faq-functions.html
zenoh,

2

Hành vi này đã được ghi lại khi React thông báo phát hành các thành phần dựa trên lớp.

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

Tự động

React.createClass có một tính năng ma thuật được tích hợp sẵn để tự động liên kết tất cả các phương thức với điều này cho bạn. Điều này có thể hơi khó hiểu đối với các nhà phát triển JavaScript không quen với tính năng này trong các lớp khác hoặc có thể gây nhầm lẫn khi họ chuyển từ React sang các lớp khác.

Do đó, chúng tôi quyết định không tích hợp tính năng này vào mô hình lớp của React. Bạn vẫn có thể ràng buộc trước các phương thức trong hàm tạo của mình nếu bạn muốn.


2

Tôi biết bài đăng này đã được vài năm, nhưng chỉ để tham khảo hướng dẫn / tài liệu React mới nhất về lỗi phổ biến này (tôi cũng đã mắc phải) từ https://reactjs.org/tutorial/tutorial.html :

Ghi chú

Để tiết kiệm việc nhập và tránh hành vi khó hiểu của việc này, chúng tôi sẽ sử dụng cú pháp hàm mũi tên cho các trình xử lý sự kiện ở đây và xa hơn bên dưới:

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

Lưu ý rằng với onClick = {() => alert ('click')}, chúng tôi đang chuyển một hàm làm phần mềm hỗ trợ onClick. React sẽ chỉ gọi hàm này sau một cú nhấp chuột. Quên () => và viết onClick = {alert ('click')} là lỗi phổ biến và sẽ kích hoạt cảnh báo mỗi khi thành phần hiển thị.


1

Cách bạn truyền phương thức this.activatePlaylist(playlist.playlist_id), sẽ gọi phương thức ngay lập tức. Bạn nên chuyển tham chiếu của phương thức cho onClicksự kiện. Thực hiện theo một trong các cách triển khai được đề cập bên dưới để giải quyết vấn đề của bạn.

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

Ở đây thuộc tính bind được sử dụng để tạo một tham chiếu của this.activatePlaylistphương thức bằng cách chuyển thisngữ cảnh và đối sốplaylist.playlist_id

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

Điều này sẽ đính kèm một chức năng vào sự kiện onClick sẽ chỉ được kích hoạt trên hành động nhấp của người dùng. Khi mã này xuất hiện, this.activatePlaylistphương thức sẽ được gọi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.