140

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?

jhamm
  • 24,124
  • 39
  • 105
  • 179

5 Answers5

259

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 
  }
}
Oleksandr T.
  • 76,493
  • 17
  • 173
  • 144
  • 1
    I don't remember it working in previous versions of `React` this way. Am I remembering wrong or has the `api` changed? – jhamm Dec 11 '15 at 14:49
  • @jhamm You are using ES6 classes and in this case you should bind context manually. – Oleksandr T. Dec 11 '15 at 14:54
  • @AlexanderT. there is one thing that I don't get it. If you bind the context with `.bind`, as you say in step 1, it's necessary to do step 2? and if it is, why? Because I think that when you use arrow function, the context is the one that it is where the function was defined, but if we are attaching the context using `.bind`, the context is already attached, right? – Rafa Romero Nov 10 '17 at 11:47
  • 2
    @Rafa Romero it is just three different options, you can use one of them – Oleksandr T. Nov 10 '17 at 11:49
  • @AlexanderT. OK! it was what I though. Then, I don understand what is going wrong in my case, because I'm binding the context to the method with the `.bind`, and sending the method down to a component using props. Then, in the component, If I call it like this: `onClick={props.myMethod()`, the method it's called automatically without doing anything and infinite times. Only works fine if I call the method using flat arrow, so in that case is not necessary to bind the context with `.bind` – Rafa Romero Nov 10 '17 at 11:55
  • 4
    There's now a section on the official React Docs website answered this question in full depth: https://reactjs.org/docs/faq-functions.html – zenoh Dec 09 '17 at 20:46
  • If you're having issues with these three options, something like this worked for me: `activatePlaylist = (playlistId) => () => { your code }` – Tyler Russell Aug 07 '19 at 20:20
  • it helps... worlded for me – Brijal Kansara Jan 31 '23 at 09:34
20

I know this post is a few years old already, but just to reference the latest React tutorial/documentation about this common mistake (I made it too) from https://reactjs.org/tutorial/tutorial.html:

Note

To save typing and avoid the confusing behavior of this, we will use the arrow function syntax for event handlers here and further below:

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

Notice how with onClick={() => alert('click')}, we’re passing a function as the onClick prop. React will only call this function after a click. Forgetting () => and writing onClick={alert('click')} is a common mistake, and would fire the alert every time the component re-renders.

CAMD_3441
  • 2,514
  • 2
  • 23
  • 38
3

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.

Community
  • 1
  • 1
David L. Walsh
  • 24,097
  • 10
  • 61
  • 46
3
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>
                       
                       )}
  • 3
    Could you add a little bit of explanation instead of just posting bits of code? It would really improve the quality of your answer – wayneOS Jun 30 '21 at 11:24
2

The way you passing the method this.activatePlaylist(playlist.playlist_id), will call the method immediately. You should pass the reference of the method to the onClick event. Follow one of the below-mentioned implementation to resolve your problem.

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

Here bind property is used to create a reference of the this.activatePlaylist method by passing this context and argument playlist.playlist_id

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

This will attach a function to the onClick event which will get triggered on user click action only. When this code exectues the this.activatePlaylist method will be called.

Community
  • 1
  • 1