¿Por qué se llama a mi onClick al renderizar? - React.js

100

Tengo un componente que he creado:

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

Cuando hago renderesta página, activatePlaylistse llama para cada uno playlisten mi map. Si me bind activatePlaylistgusta

activatePlaylist.bind(this, playlist.playlist_id)

También puedo usar una función anónima:

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

entonces funciona como se esperaba. ¿Por qué pasó esto?

jhamm
fuente

Respuestas:

191

Necesita pasar a la onClick referencia a la función, cuando lo hace así activatePlaylist( .. ), llama a la función y pasa al onClickvalor que devolvió activatePlaylist. Puede utilizar una de estas tres opciones:

1 . utilizando.bind

activatePlaylist.bind(this, playlist.playlist_id)

2 . usando la función de flecha

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

3 . o función de retorno deactivatePlaylist

activatePlaylist(playlistId) {
  return function () {
     // you code 
  }
}
Alexander T.
fuente
No recuerdo que haya funcionado en versiones anteriores de Reactesta forma. ¿Estoy recordando mal o ha apicambiado?
jhamm
@jhamm Estás usando clases de ES6 y, en este caso, debes vincular el contexto manualmente.
Alexander T.
@AlexanderT. hay una cosa que no lo entiendo. Si enlaza el contexto con .bind, como dice en el paso 1, ¿es necesario realizar el paso 2? y si es así, ¿por qué? Porque creo que cuando usas la función de flecha, el contexto es el que es donde se definió la función, pero si estamos adjuntando el contexto usando .bind, el contexto ya está adjunto, ¿verdad?
Rafa Romero
2
@Rafa Romero son solo tres opciones diferentes, puedes usar una de ellas
Alexander T.
2
Ahora hay una sección en el sitio web oficial de React Docs que responde a esta pregunta en profundidad: reactjs.org/docs/faq-functions.html
zenoh
2

Este comportamiento se documentó cuando React anunció el lanzamiento de componentes basados ​​en clases.

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

Encuadernación automática

React.createClass tiene una función mágica incorporada que enlaza todos los métodos a esto automáticamente para usted. Esto puede resultar un poco confuso para los desarrolladores de JavaScript que no están acostumbrados a esta función en otras clases, o puede resultar confuso cuando se mueven de React a otras clases.

Por lo tanto, decidimos no tener esto integrado en el modelo de clase de React. Aún puede vincular métodos explícitamente en su constructor si lo desea.

David L. Walsh
fuente
2

Sé que esta publicación ya tiene algunos años, pero solo para hacer referencia al último tutorial / documentación de React sobre este error común (yo también lo cometí) de https://reactjs.org/tutorial/tutorial.html :

Nota

Para evitar escribir y evitar el comportamiento confuso de esto, usaremos la sintaxis de la función de flecha para los controladores de eventos aquí y más abajo:

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

Observe cómo con onClick = {() => alert ('click')}, estamos pasando una función como la propiedad onClick. React solo llamará a esta función después de un clic. Olvidar () => y escribir onClick = {alert ('click')} es un error común y dispararía la alerta cada vez que el componente se vuelve a renderizar.

CAM_344
fuente
1

La forma en que pasa el método this.activatePlaylist(playlist.playlist_id)llamará al método inmediatamente. Debe pasar la referencia del método al onClickevento. Siga una de las implementaciones mencionadas a continuación para resolver su problema.

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

Aquí la propiedad de vinculación se usa para crear una referencia del this.activatePlaylistmétodo pasando thiscontexto y argumentoplaylist.playlist_id

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

Esto adjuntará una función al evento onClick que se activará solo en la acción de clic del usuario. Cuando este código se ejecute, se llamará al this.activatePlaylistmétodo.

Shrishail Uttagi
fuente