React js onClick 无法将值传递给方法

IT技术 javascript reactjs
2021-01-26 22:18:11

我想读取 onClick 事件值属性。但是当我点击它时,我在控制台上看到了这样的东西:

SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target

我的代码工作正常。当我运行时,我可以看到{column}但无法在 onClick 事件中获取它。

我的代码:

var HeaderRows = React.createClass({
  handleSort:  function(value) {
    console.log(value);
  },
  render: function () {
    var that = this;
    return(
      <tr>
        {this.props.defaultColumns.map(function (column) {
          return (
            <th value={column} onClick={that.handleSort} >{column}</th>
          );
        })}
        {this.props.externalColumns.map(function (column) {
          // Multi dimension array - 0 is column name
          var externalColumnName = column[0];
          return ( <th>{externalColumnName}</th>);
        })}
      </tr>
    );
  }
});

如何将值传递给onClickReact js 中事件?

6个回答

简单的方法

使用箭头函数:

return (
  <th value={column} onClick={() => this.handleSort(column)}>{column}</th>
);

这将创建一个handleSort使用正确参数调用的新函数

更好的方法

将其提取到子组件中。 在渲染调用中使用箭头函数的问题是它每次都会创建一个新函数,最终导致不必要的重新渲染。

如果你创建了一个子组件,你可以传递 handler 并使用 props 作为参数,然后只有当 props 改变时才会重新渲染(因为处理程序引用现在永远不会改变):

子组件

class TableHeader extends Component {
  handleClick = () => {
    this.props.onHeaderClick(this.props.value);
  }

  render() {
    return (
      <th onClick={this.handleClick}>
        {this.props.column}
      </th>
    );
  }
}

主要成分

{this.props.defaultColumns.map((column) => (
  <TableHeader
    value={column}
    onHeaderClick={this.handleSort}
  />
))}

旧的简单方式 (ES5)

使用.bind通过所需要的参数,这样你要绑定与组件方面的功能:

return (
  <th value={column} onClick={this.handleSort.bind(this, column)}>{column}</th>
);
当我像你的代码一样使用时,react 会发出警告。我将代码更改为 onClick={that.onClick.bind(null,column)}
2021-03-19 22:18:11
@SimonH 该事件将作为最后一个参数传递,在您通过bind.
2021-03-21 22:18:11
这对性能来说不是坏事吗?不会在每次渲染时创建一个新函数吗?
2021-03-31 22:18:11
您将如何将它与<a>需要传递事件标签一起使用,以便使用preventDefault()
2021-04-04 22:18:11
@AndrewMcLagan 是的。发现这是为了描述规则和最高效的解决方案。
2021-04-04 22:18:11

这里有很好的答案,我同意@Austin Greco(带有单独组件的第二个选项)
还有另一种我喜欢的方式,currying
您可以做的是创建一个函数,该函数接受一个参数(您的参数)并返回另一个接受另一个参数的函数(在本例中为 click 事件)。那么你就可以随意使用它。

ES5:

handleChange(param) { // param is the argument you passed to the function
    return function (e) { // e is the event object that returned

    };
}

ES6:

handleChange = param => e => {
    // param is the argument you passed to the function
    // e is the event object that returned
};

你会这样使用它:

<input 
    type="text" 
    onChange={this.handleChange(someParam)} 
/>

这是此类用法的完整示例:

请注意,此方法无法解决在每次渲染时创建新实例的问题。
与其他内联处理程序相比,我更喜欢这种方法,因为在我看来,这种方法更简洁易读。

编辑:
正如下面评论中所建议的,您可以缓存/记忆函数的结果。

这是一个简单的实现:

如果您满足@travellingprog 的建议,这就是完美的答案
2021-03-13 22:18:11
任何人都可以提供链接或解释这种缓存机制的工作原理吗?谢谢。
2021-03-20 22:18:11
这应该是公认的答案。真的很容易实现,你不需要创建任何其他组件或以不同的方式绑定。谢谢!
2021-03-24 22:18:11
如果使用柯里化,则每次渲染时都会创建新函数。传递箭头函数时会出现相同的性能问题。
2021-03-27 22:18:11
看起来更好,但从性能的角度来看,柯里化并没有真正的帮助,因为如果你使用相同的参数调用 handleChange 两次,你会得到两个 JS 引擎认为是独立对象的函数,即使它们做同样的事情. 所以你仍然可以重新渲染。出于性能考虑,您需要缓存 handleChange 的结果以获得性能优势。喜欢handleChange = param => cache[param] || (e => { // the function body })
2021-04-02 22:18:11

如今,有了 ES6,我觉得我们可以使用更新的答案。

return (
  <th value={column} onClick={()=>this.handleSort(column)} >{column}</th>
);

基本上,(对于任何不知道的人)因为onClick期望传递给它的函数,bind之所以起作用是因为它创建了一个函数的副本。相反,我们可以传递一个箭头函数表达式,它简单地调用我们想要的函数,并保留this. 你永远不需要render在 React 中绑定方法,但是如果由于某种原因你丢失this了你的组件方法之一:

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}
你永远不需要绑定,render()因为它是由 React 调用的。如果有的话,您需要bind事件处理程序,并且仅当您不使用箭头时。
2021-03-10 22:18:11
请注意,最好在构造函数期间传递propssuper()this.props将是未定义的,这可能会引起混淆。
2021-03-16 22:18:11
谢谢爱可如。好的,所以您是说,如果您将 foo 方法声明为类本身的箭头函数,然后使用 this 上下文引用它,那么它只创建一次,而不是在 onClick 中声明它,每次单击时它都会创建相同的函数按钮。我的想法是否正确。
2021-03-17 22:18:11
@zuckerburg onClick={() => alert('hi')} 不会立即发出警报, onClick={this.showAlert} 也不会,因为在这两种情况下,您都在传递(不调用)一个函数。
2021-03-31 22:18:11
达到什么目的?您可以在功能组件中定义一个处理程序并传递它。每次渲染都会有一个不同的功能,所以如果你已经用分析器确定它会给你带来性能问题(并且只有当你真的确定这一点时!),请考虑使用类。
2021-04-03 22:18:11

[[h/t to @E.Sundin在评论中链接]

最佳答案(匿名函数或绑定)会起作用,但它不是最高效的,因为它会为函数生成的每个实例创建事件处理程序的副本map()

这是从ESLint-plugin-react执行此操作的最佳方法的解释

物品清单

在渲染中绑定的一个常见用例是渲染列表时,每个列表项都有一个单独的回调:

const List = props => (
      <ul>
        {props.items.map(item =>
          <li key={item.id} onClick={() => console.log(item.id)}>
            ...
          </li>
        )}
      </ul>
    );

与其这样做,不如将重复的部分拉入其自己的组件中:

const List = props => (
      <ul>
        {props.items.map(item =>
          <ListItem 
            key={item.id} 
            item={item} 
            onItemClick={props.onItemClick} // assume this is passed down to List
           />
        )}
      </ul>
    );


const ListItem = props => {
  const _onClick = () => {
    console.log(props.item.id);
  }
    return (
      <li onClick={_onClick}>
        ...
      </li>
    );

});

这将加速渲染,因为它避免了在每次渲染时创建新函数(通过绑定调用)的需要。

嗯,我不明白这是如何提高性能的?不会每次都调用 ListItem 函数,因此每次渲染都会创建 _onClick 函数。
2021-03-10 22:18:11
react 是否使用 call/apply 调用这些函数,然后在幕后避免使用 bind 内部?
2021-03-12 22:18:11
有没有办法使用无状态组件来做到这一点?
2021-03-16 22:18:11
我远不是这里的专家,但据我所知,在“正确”模式中,只有一个处理程序实例,并且它传递了组件调用它的任何实例的 prop。在绑定示例(即“错误”模式)中,每个实例化组件都有一个处理程序实例。它的内存相当于编写相同的函数三十次,反之则编写一次并在需要时调用它。
2021-03-28 22:18:11
@CarlosMartinez 好眼,我更新了这个例子——它们首先应该是无状态功能组件(SFC)。通常,如果某个组件从不使用this.state,您可以安全地将其替换为 SFC。
2021-04-05 22:18:11

这是我的方法,不确定它有多糟糕,请评论

在可点击元素中

return (
    <th value={column} onClick={that.handleSort} data-column={column}>   {column}</th>
);

接着

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}
可以在现代浏览器(包括 IE11)上以这种方式直接访问数据集:e.currentTarget.dataset.column
2021-03-13 22:18:11
对于一个对象,你需要做encodeURIComponent(JSON.stringify(myObj)),然后解析它,JSON.parse(decodeURIComponent(myObj))对于函数,我很确定这在没有 eval 或 new Function() 的情况下不起作用,这两者都应该避免。由于这些原因,我不使用数据属性在 React/JS 中传递数据。
2021-03-15 22:18:11
我认为这是一个很好的解决方案,因为它非常简单。但它只适用于字符串值,如果你想要一个对象它不起作用。
2021-03-19 22:18:11
这是我想到的一种方法,感觉有点hacky,但避免了创建新组件。我不确定与拉入单独的组件相比,getAttribute 在性能方面是更好还是更差。
2021-03-25 22:18:11
我想补充一点,我不经常使用它,而且只用于次要的事情。但通常我只是创建一个组件并将数据作为道具传递给它。然后要么处理该新组件内的点击,要么将 onClick 函数传递给该组件。布兰登回答中解释了喜欢
2021-03-30 22:18:11