Pourquoi mon onClick est-il appelé lors du rendu? - React.js

100

J'ai un composant que j'ai créé:

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

Lorsque je rendercette page, activatePlaylistest appelé pour chacun playlistdans mon map. Si bind activatePlaylistj'aime:

activatePlaylist.bind(this, playlist.playlist_id)

Je peux également utiliser une fonction anonyme:

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

alors cela fonctionne comme prévu. Pourquoi cela arrive-t-il?

jhamm
la source

Réponses:

191

Vous devez passer à la onClick référence à la fonction, lorsque vous faites comme cela, activatePlaylist( .. )vous appelez la fonction et passez à la onClickvaleur renvoyée par activatePlaylist. Vous pouvez utiliser l'une de ces trois options:

1 . en utilisant.bind

activatePlaylist.bind(this, playlist.playlist_id)

2 . en utilisant la fonction fléchée

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

3 . ou retourne la fonction deactivatePlaylist

activatePlaylist(playlistId) {
  return function () {
     // you code 
  }
}
Alexander T.
la source
Je ne me souviens pas que cela fonctionnait dans les versions précédentes de Reactcette façon. Est-ce que je me souviens mal ou a- apit-il changé?
jhamm
@jhamm Vous utilisez des classes ES6 et dans ce cas, vous devez lier le contexte manuellement.
Alexander
@AlexanderT. il y a une chose que je ne comprends pas. Si vous liez le contexte avec .bind, comme vous le dites à l'étape 1, il est nécessaire de faire l'étape 2? et si c'est le cas, pourquoi? Parce que je pense que lorsque vous utilisez la fonction de flèche, le contexte est celui dans lequel la fonction a été définie, mais si nous attachons le contexte en utilisant .bind, le contexte est déjà attaché, non?
Rafa Romero
2
@Rafa Romero, ce ne sont que trois options différentes, vous pouvez en utiliser une
Alexander T.
2
Il y a maintenant une section sur le site officiel de React Docs qui a répondu à cette question en profondeur: reactjs.org/docs/faq-functions.html
zenoh
2

Ce comportement a été documenté lorsque React a annoncé la sortie de composants basés sur les classes.

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

Liaison automatique

React.createClass a une fonction magique intégrée qui lie automatiquement toutes les méthodes à cela pour vous. Cela peut être un peu déroutant pour les développeurs JavaScript qui ne sont pas habitués à cette fonctionnalité dans d'autres classes, ou cela peut être déroutant lorsqu'ils passent de React à d'autres classes.

Par conséquent, nous avons décidé de ne pas avoir cela intégré dans le modèle de classe de React. Vous pouvez toujours pré-lier explicitement les méthodes dans votre constructeur si vous le souhaitez.

David L. Walsh
la source
2

Je sais que cet article a déjà quelques années, mais juste pour faire référence au dernier tutoriel / documentation React sur cette erreur courante (je l'ai fait aussi) à partir de https://reactjs.org/tutorial/tutorial.html :

Remarque

Pour enregistrer la saisie et éviter le comportement déroutant de ceci, nous utiliserons la syntaxe de la fonction flèche pour les gestionnaires d'événements ici et plus loin ci-dessous:

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

Remarquez comment avec onClick = {() => alert ('click')}, nous passons une fonction en tant que prop onClick. React n'appellera cette fonction qu'après un clic. Oublier () => et écrire onClick = {alert ('click')} est une erreur courante, et déclencherait l'alerte à chaque fois que le composant se re-rend.

CAM_344
la source
1

La façon dont vous transmettez la méthode this.activatePlaylist(playlist.playlist_id)appellera la méthode immédiatement. Vous devez transmettre la référence de la méthode à l' onClickévénement. Suivez l'une des implémentations mentionnées ci-dessous pour résoudre votre problème.

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

Ici, la propriété bind est utilisée pour créer une référence de la this.activatePlaylistméthode en passant le thiscontexte et l'argumentplaylist.playlist_id

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

Cela attachera une fonction à l'événement onClick qui sera déclenché uniquement par l'action de clic de l'utilisateur. Lorsque ce code sera exécuté, la this.activatePlaylistméthode sera appelée.

Shrishail Uttagi
la source