React - 触发表行上的单击事件

Ran*_*air 11 javascript reactjs

我无法从React中的表行调用click事件.以下是我的代码.我有一个单独的函数来单独填充行,但似乎我正在搞乱绑定信息.

import React, {Component, PropTypes} from 'react';
import Header from './Header';

export default class SongData extends Component {
 constructor(props, context) {
    super(props, context);
 }

isEmpty(obj) {
    return Object.keys(obj).length === 0;
}

fetchDetails(song) {
    console.log(song);
}

renderResultRows(data) {
    var self = this;
    return data.map(function(song) {
        return (
            <tr onClick={self.fetchDetails(song)}>
                <td data-title="Song">{song.S_SONG}</td>
                <td data-title="Movie">{song.S_MOVIE}</td>
                <td data-title="Year">{song.S_YEAR}</td>
            </tr>
        );
    }.bind(this));
}

render() {
    return (
        <div id="no-more-tables">
            <table className="table table-hover table-bordered table-striped">
                <thead>
                    <tr>
                        <th>Song</th>
                        <th>Movie</th>
                        <th>Year</th>
                    </tr>
                </thead>
                <tbody>
                    {!this.isEmpty(this.props.searchResult)
                        ? this.renderResultRows(this.props.searchResult)
                        : ''}
                </tbody>
            </table>
        </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

}

ctr*_*usb 30

首先,您将一个已评估的函数调用传递给您的onClick属性.

隔离地查看以下代码:

 function foo(name) { return 'hello ' + name; }

 foo('bob');
Run Code Online (Sandbox Code Playgroud)

您希望输出为foo('bob')"hello bob".

如果我将它传递给onClick道具,那就完全相同了.例如:

 <button onClick={foo('bob')}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我只是将一个字符串传递给onClick按钮的道具.的onClick(和其他事件的道具)希望被提供的功能(或ref).我将进一步说明这一点.

其次我看你有正确的意向试图维持使用的组合为你的函数正确的范围const self = this和bind.使用ES6/2015中的匿名函数可以更轻松地完成此操作,这些函数始终保持声明它们的声明范围.

然后我可以将您的代码更新为以下内容:

renderResultRows(data) {
    return data.map((song) => {  // anon func maintains scope!
        // Pass in a function to our onClick, and make it anon
        // to maintain scope.  The function body can be anything
        // which will be executed on click only.  Our song value
        // is maintained via a closure so it works.
        return (
            <tr onClick={() => this.fetchDetails(song)}>
                <td data-title="Song">{song.S_SONG}</td>
                <td data-title="Movie">{song.S_MOVIE}</td>
                <td data-title="Year">{song.S_YEAR}</td>
            </tr>
        );
    });  // no need to bind with anon function
}
Run Code Online (Sandbox Code Playgroud)

但这仍然不是最佳的.当使用这样的匿名语法(例如<foo onClick={() => { console.log('clicked') })时,我们在每个渲染上创建一个新函数.如果您使用纯组件(即仅在提供新的prop实例时应该重新呈现的组件 - 这个检查通过浅层比较执行),这可能是一个问题.总是尝试尽早创建函数,例如在构造函数中或通过类属性(如果使用babel阶段1),这样您总是传入相同的引用.

但是,对于您的示例,您需要将值"传递"到每个onClick处理程序中.为此,您可以使用以下方法:

fetchSongDetails = () => {
  const song = e.target.getAttribute('data-item');
  console.log('We need to get the details for ', song);
}

renderResultRows(data) {
    return data.map((song, index) => {  // anon func maintains scope!
        // Pass in a function to our onClick, and make it anon
        // to maintain scope.  The function body can be anything
        // which will be executed on click only.  Our song value
        // is maintained via a closure so it works.
        return (
            <tr key={index} data-item={song} onClick={this.fetchSongDetails}>
                <td data-title="Song">{song.S_SONG}</td>
                <td data-title="Movie">{song.S_MOVIE}</td>
                <td data-title="Year">{song.S_YEAR}</td>
            </tr>
        );
    });  // no need to bind with anon function
}
Run Code Online (Sandbox Code Playgroud)

这是一个更好的方法.另请注意,我key为每个生成的行添加了一个prop.这是另一种反应最佳实践,因为反应将使用其差异算法中的唯一键标识符.


我强烈推荐以下阅读:

  • 看来你的fetchSongDetails()回调中的e.target引用了被点击的表格单元格,而不是行.使用e.currentTarget提供所需的行引用.(顺便说一下,感谢您花时间写出如此全面,简洁,内容丰富的答案.) (12认同)
  • 在函数“fetchSongDetails()”中,您使用: const Song = e.target.getAttribute('data-item'); 但在“fetchSongDetails()”内的“song”变量中,它不会返回真正的“song”对象。您询问“html attribute”“data-item”,它将返回不可用的文字字符串“object Object”。它不会返回真正的“歌曲”对​​象。 (2认同)

Ida*_*gan 6

除了@ctrlplusb answer 之外,我还想建议另一种在 click 事件中传递对象的方法:

// 歌曲组件

import React from 'react';
import RowComponent from './RowComponent';

export default class SongData extends React.PureComponent {

  fetchDetails(songObj) {
    // whatever
  }

  renderResultRows(data) {
    return data.map(songObj => (
      <RowComponent
        key={songObj.id}
        data={songObj}
        onClick={this.fetchDetails}
      />;
  }

  render() {

    const { data } = this.props;

    return (
      <div>
        <table>
         <thead>
         </thead>
         <tbody>
          {
            this.renderResultRows(data)
          }
         </tbody>
        </table>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

// 行组件

import React from 'react';

export function RowComponent(props) {
  const { data, onClick } = props;

  function handleClick() {
    onClick(data);
  }

  return (
    <tr onClick={handleClick}>
      <td data-title="Song">{data.S_SONG}</td>
      <td data-title="Movie">{data.S_MOVIE}</td>
      <td data-title="Year">{data.S_YEAR}</td>
    </tr>
  );
}
Run Code Online (Sandbox Code Playgroud)