如何在行内使 onClick 起作用 - reactjs

19

我正在尝试使用 reactjs 中的表格添加点击功能。 我的第一次尝试是使整行可点击。 下面是我的代码:

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

这不起作用。接着我尝试在表格中添加一个按钮:

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

那个方法也没有起作用。我在应用程序中有其他onClick的功能,但是如何使其与表格一起工作呢?

3个回答

35

您的问题是用户创建表格行的函数未绑定到React组件。 this 的值将不是您的React组件,因此handleClick 不会存在于 this 的属性中。

请尝试:

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

如果您希望它在所有浏览器上都能工作,可以使用Underscore的bind


完全有道理。我不明白最后一句话的意思,“或者使用下划线绑定,如果你想让它在所有浏览器上都能工作”?你能给我展示一个例子吗? - jhamm
".bind在旧版浏览器中不受支持。Underscore是一个流行的库,其中包括为旧版浏览器添加bind支持的功能。" - Mark Bolusmjak
2
另外,如果您想知道单击了哪个用户行,可以将其作为绑定的另一个参数添加:.bind(this, user),并修改单击处理程序为:handleClick: function (user, e) { - joakimbeng
谢谢您的回复,虽然这是旧的内容,但是我想补充一下@joakimbeng的解决方案,在onclick事件中应该像这样写:onClick={ (e) => this.props.onSelect(e, user)} - SSH This

5

我对React很新,请问这种情况怎么处理? 只需要把它包装在另一个函数中,那个函数就会保持闭包作用域并正确调用它。

我不知道这是否是一种不好的做法或者性能上的差异,但是它似乎能够工作...

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

3
事实证明,这是一种不良的做法,尤其是在数据集中存在大量行的情况下,因为会建立大量函数,而只需要一个函数即可。但我将保留它作为一个反面例子。 - Matt Broekhuis
每次渲染都在子组件属性中添加新功能是一种不好的实践,因为这会改变虚拟DOM状态,并迫使React在父级(table)每次重新渲染时重新渲染子组件(tr)。 - Partha Pal

0

绑定会创建一个新对象。因此,如果您为N个员工绑定函数,则会低效地创建N个新函数。更优雅的方法是仅绑定一次函数,并传递对每一行的引用。您的原始代码非常接近。这是我建议的:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接