Why is my onClick being called on render? - React.

2019-01-13 00:49发布

问题:

I have a component that I have created:

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

When I render this page, activatePlaylist is called for each playlist in my map. If I bind activatePlaylist like:

activatePlaylist.bind(this, playlist.playlist_id)

I can also use an anonymous function:

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

then it works as expected. Why does this happen?

回答1:

You need pass to onClick reference to function, when you do like this activatePlaylist( .. ) you call function and pass to onClick value that returned from activatePlaylist. You can use one of these three options:

1. using .bind

activatePlaylist.bind(this, playlist.playlist_id)

2. using arrow function

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

3. or return function from activatePlaylist

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


回答2:

This behaviour was documented when React announced the release of class based components.

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

Autobinding

React.createClass has a built-in magic feature that bound all methods to this automatically for you. This can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes.

Therefore we decided not to have this built-in into React's class model. You can still explicitly prebind methods in your constructor if you want.