Почему мой onClick вызывается при рендеринге? — React.js

#javascript #reactjs

#javascript #reactjs #redux

Вопрос:

У меня есть компонент, который я создал:

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

тогда все работает так, как ожидалось. Почему это происходит?

Ответ №1:

Вам нужно передать onClick ссылку на функцию, когда вы делаете подобным образом, activatePlaylist( .. ) вы вызываете функцию и передаете onClick значение, возвращенное из activatePlaylist . Вы можете использовать один из этих трех вариантов:

1. использование .bind

 activatePlaylist.bind(this, playlist.playlist_id)
  

2. использование функции arrow

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

3. или возвращающая функция из activatePlaylist

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

Комментарии:

1. Я не помню, чтобы это работало в предыдущих версиях React таким образом. Я неправильно помню или api изменилось?

2. @jhamm Вы используете классы ES6, и в этом случае вам следует привязать контекст вручную.

3. @AlexanderT. есть одна вещь, которую я не понимаю. Если вы связываете контекст с .bind , как вы сказали на шаге 1, необходимо выполнить шаг 2? и если это так, то почему? Потому что я думаю, что когда вы используете функцию arrow, контекст — это тот, в котором была определена функция, но если мы подключаем контекст с помощью .bind , контекст уже подключен, верно?

4. @Rafa Romero это всего лишь три разных варианта, вы можете использовать один из них

5. Теперь на официальном веб-сайте React Docs есть раздел, в котором дан исчерпывающий ответ на этот вопрос: reactjs.org/docs/faq-functions.html

Ответ №2:

Я знаю, что этому сообщению уже несколько лет, но просто чтобы сослаться на последнее руководство / документацию по React об этой распространенной ошибке (я тоже ее допустил) от https://reactjs.org/tutorial/tutorial.html:

Примечание

Чтобы сэкономить на вводе текста и избежать при этом запутанного поведения, мы будем использовать синтаксис функции arrow для обработчиков событий здесь и далее ниже:

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

Обратите внимание, как с помощью onClick={() => alert (‘щелчок’)} мы передаем
функционирует как реквизит onClick. React вызовет эту функцию только после
щелчок. Забыть () => и написать onClick={alert (‘щелчок’)} — это
распространенная ошибка, и будет выдавать предупреждение каждый раз, когда компонент
повторный рендеринг.

Комментарии:

1. Перед ним у меня была функция со стрелкой, подобная этой, и она все еще активировалась.

Ответ №3:

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

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

Автоматическая привязка

React.createClass имеет встроенную волшебную функцию, которая автоматически привязывает все методы к этому для вас. Это может немного сбить с толку разработчиков JavaScript, которые не привыкли к этой функции в других классах, или это может сбить с толку при переходе с React на другие классы.

Поэтому мы решили не использовать это встроенное в модель класса React. Вы все еще можете явно предварительно привязать методы в своем конструкторе, если хотите.

Ответ №4:

 import React from 'react';
import { Page ,Navbar, Popup} from 'framework7-react';

class AssignmentDashboard extends React.Component {
    constructor(props) {
      super(props);
      this.state = {

    }

    
      onSelectList=(ProjectId)=>{
          return(

            console.log(ProjectId,"projectid")
          )

      }
            
render() {
       
    return (   
      
 <li key={index} onClick={()=> this.onSelectList(item.ProjectId)}></li>
                       
                       )}
  

Комментарии:

1. Не могли бы вы добавить немного объяснений вместо того, чтобы просто публиковать фрагменты кода? Это действительно улучшило бы качество вашего ответа

Ответ №5:

То, как вы передаете метод 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 метод.