Warum wird mein onClick beim Rendern aufgerufen? - React.js

97

Ich habe eine Komponente, die ich erstellt habe:

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

Wenn ich renderdiese Seite habe, activatePlaylistwird für jeden playlistin meinem aufgerufen map. Wenn ich bind activatePlaylistmag:

activatePlaylist.bind(this, playlist.playlist_id)

Ich kann auch eine anonyme Funktion verwenden:

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

dann funktioniert es wie erwartet. Warum passiert das?

jhamm
quelle

Antworten:

186

Sie müssen übergeben, um auf die Funktion zu onClick verweisen . Wenn Sie dies mögen activatePlaylist( .. ), rufen Sie function auf und übergeben an den onClickWert, der von zurückgegeben wurde activatePlaylist. Sie können eine dieser drei Optionen verwenden:

1 . mit.bind

activatePlaylist.bind(this, playlist.playlist_id)

2 . mit Pfeilfunktion

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

3 . oder Rückgabefunktion vonactivatePlaylist

activatePlaylist(playlistId) {
  return function () {
     // you code 
  }
}
Alexander T.
quelle
Ich erinnere mich nicht, dass es in früheren Versionen Reactdieser Art funktioniert hat . Erinnere ich mich falsch oder hat sich das apigeändert?
JHamm
@jhamm Sie verwenden ES6-Klassen und in diesem Fall sollten Sie den Kontext manuell binden.
Alexander T.
@ AlexanderT. Es gibt eine Sache, die ich nicht verstehe. Wenn Sie den Kontext binden .bind, wie Sie in Schritt 1 sagen, ist es notwendig, Schritt 2 auszuführen? und wenn ja, warum? Weil ich denke, wenn Sie die Pfeilfunktion verwenden, ist der Kontext derjenige, in dem die Funktion definiert wurde, aber wenn wir den Kontext mit .bindanhängen, ist der Kontext bereits angehängt, oder?
Rafa Romero
2
@ Rafa Romero es sind nur drei verschiedene Optionen, Sie können eine davon verwenden
Alexander T.
2
Es gibt jetzt einen Abschnitt auf der offiziellen React Docs-Website, der diese Frage ausführlich beantwortet hat: reactjs.org/docs/faq-functions.html
zenoh
2

Dieses Verhalten wurde dokumentiert, als React die Veröffentlichung klassenbasierter Komponenten ankündigte.

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

Autobinding

React.createClass verfügt über eine integrierte magische Funktion, die alle Methoden automatisch für Sie daran bindet. Dies kann für JavaScript-Entwickler, die diese Funktion in anderen Klassen nicht gewohnt sind, etwas verwirrend sein, oder es kann verwirrend sein, wenn sie von React zu anderen Klassen wechseln.

Aus diesem Grund haben wir beschlossen, dieses Modell nicht in das Klassenmodell von React zu integrieren. Sie können Methoden in Ihrem Konstruktor weiterhin explizit vorbinden, wenn Sie möchten.

David L. Walsh
quelle
2

Ich weiß, dass dieser Beitrag bereits einige Jahre alt ist, aber nur um auf das neueste React-Tutorial / die neueste Dokumentation zu diesem häufigen Fehler (ich habe es auch gemacht) von https://reactjs.org/tutorial/tutorial.html zu verweisen :

Hinweis

Um die Eingabe zu sparen und das verwirrende Verhalten zu vermeiden, verwenden wir hier und weiter unten die Pfeilfunktionssyntax für Ereignishandler:

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

Beachten Sie, dass wir mit onClick = {() => alert ('click')} eine Funktion als onClick-Requisite übergeben. React ruft diese Funktion erst nach einem Klick auf. Das Vergessen () => und das Schreiben von onClick = {alert ('click')} ist ein häufiger Fehler und würde die Warnung jedes Mal auslösen, wenn die Komponente erneut gerendert wird.

CAM_344
quelle
1

Die Art und Weise, wie Sie die Methode übergeben this.activatePlaylist(playlist.playlist_id), ruft die Methode sofort auf. Sie sollten den Verweis der Methode an das onClickEreignis übergeben. Befolgen Sie eine der unten aufgeführten Implementierungen, um Ihr Problem zu beheben.

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

Hier wird die Eigenschaft bind verwendet, um eine Referenz der this.activatePlaylistMethode zu erstellen, indem thisKontext und Argument übergeben werdenplaylist.playlist_id

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

Dadurch wird dem onClick-Ereignis eine Funktion hinzugefügt, die nur bei einer Benutzerklickaktion ausgelöst wird. Wenn dieser Code ausgeführt wird, wird die this.activatePlaylistMethode aufgerufen.

Shrishail Uttagi
quelle