jhamm
jhamm

Reputation: 25062

How to get a onClick to work in a row - reactjs

I am trying to get a click even to work with a table in reactjs. My first attempt was to make the whole row clickable. Here is my code:

var UserList = React.createClass({
  getInitialState: function() {
    return getUsers();
  },
  handleClick: function(e) {
    console.log("clicked");
  },
  render: function() {
    var users = this.state.users.map(function(user) {
      return (
        <tr onClick={this.handleClick}>
          <td>{user.name}</td>
          <td>{user.age}</td>
          <td></td>
        </tr>
      );
    });
    return(
      <div className="container">
        <table className="table table-striped">
          <thead>
            <tr>
              <th>Name</th>
              <th>Age</th>
              <th>Full Detail</th>
            </tr>
          </thead>
            <tbody>
              {users}
            </tbody>
        </table>
      </div>
    );
  }
});

This did not work. I then tried to add a button in the table:

<button className="btn" onClick={this.handleClick}>Full Detail</button>

That also did not work. I have other onClick's working throughout my app, but how do I make this work with a table?

Upvotes: 19

Views: 42410

Answers (3)

Antuan
Antuan

Reputation: 519

Binding creates a new object. Thus if you bind your function for N employees, you are inefficiently creating N new functions. A more elegant approach is to bind the function once, and pass a reference to every row. Your original code was quite close. This is what I would suggest:

 handleClick = e => {
    const user = this.state.users.find(u => u.uuid == e.target.dataset.uui)
    console.log("clicked");
  },
  render() {
    return(
      <div className="container">
        <table className="table table-striped">
          <thead>
            <tr>
              <th>Name</th>
              <th>Age</th>
              <th>Full Detail</th>
            </tr>
          </thead>
            <tbody>
              {this.state.users.map(user => 
                (
                 <tr data-uuid={user.uuid} onClick={this.handleClick}>
                   <td>{user.name}</td>
                   <td>{user.age}</td>
                    <td>{user.details || ''}</td>      
                 </tr>
                )
              )}
  
            </tbody>
        </table>
      </div>
    );
  }
});

Upvotes: 0

Matt Broekhuis
Matt Broekhuis

Reputation: 2075

I'm new to react. How about this? You just wrap it in another function, then that function holds the closure scope and it calls it correctly.

No idea if this is bad practice or the performance difference, but it seems to work...

var users = this.state.users.map(function(user) {
  return (
    <tr onClick={()=>this.handleClick(user)}>
      <td>{user.name}</td>
      <td>{user.age}</td>
      <td></td>
    </tr>
  );}.bind(this);
});

Upvotes: 5

Mark Bolusmjak
Mark Bolusmjak

Reputation: 24419

Your problem is the function of user that creates the table row is not bound to your react component. The value of this will not be your react component and handleClick will not exist as a property of this.

Try

var users = this.state.users.map(function(user) {
  return (
    <tr onClick={this.handleClick}>
      <td>{user.name}</td>
      <td>{user.age}</td>
      <td></td>
    </tr>
  );}.bind(this);
});

Or use Underscore's bind if you want it to work on all browsers.

Upvotes: 35

Related Questions