Чому мій onClick викликається при відтворенні? - React.js


100

У мене є компонент, який я створив:

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

тоді це працює, як очікувалося. Чому так трапляється?

Відповіді:


191

Вам потрібно перейти до 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, і в цьому випадку вам слід прив'язати контекст вручну.
Олександр Т.

@AlexanderT. є одна річ, що я не розумію. Якщо ви зв'язуєте контекст з .bind, як ви сказали на кроці 1, необхідно зробити крок 2? а якщо так, то чому? Тому що я думаю, що коли ви використовуєте функцію зі стрілкою, контекст є тим, що саме там була визначена функція, але якщо ми додаємо контекст, використовуючи .bind, контекст вже приєднаний, чи не так?
Рафа Ромеро,

2
@Rafa Romero це лише три різні варіанти, ви можете використовувати один з них
Олександр Т.

2
Зараз на офіційному веб-сайті React Docs розділ повністю відповів на це запитання: responsejs.org/docs/faq-functions.html
zenoh

2

Ця поведінка була задокументована, коли React оголосив про випуск компонентів на основі класу.

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

Автозв’язування

React.createClass має вбудовану магічну функцію, яка автоматично прив’язує до вас усі методи. Це може трохи заплутати розробників JavaScript, які не звикли до цієї функції в інших класах, або заплутати, коли вони переходять з React до інших класів.

Тому ми вирішили не вбудовувати цю модель класу в React. Ви все ще можете явно попередньо прив’язати методи у своєму конструкторі, якщо хочете.


2

Я знаю, що цій публікації вже кілька років, але лише для посилання на останній підручник / документацію 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. React викликає цю функцію лише після клацання. Забуття () => та написання onClick = {alert ('click')} є типовою помилкою, і це спрацьовує щоразу, коли компонент повторно відображається.


1

Спосіб передачі методу this.activatePlaylist(playlist.playlist_id)негайно викликає метод. Вам слід передати посилання на метод до onClickподії. Щоб вирішити проблему, дотримуйтесь одного із зазначених нижче варіантів.

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

Тут властивість bind використовується для створення посилання на this.activatePlaylistметод, передаючи thisконтекст і аргументplaylist.playlist_id

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

Це приєднає функцію до події onClick, яка ініціюватиметься лише при дії користувача. Коли цей код виконує this.activatePlaylistметод, буде викликаний метод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.