React.js 中的 OnClick 事件绑定

Posted

技术标签:

【中文标题】React.js 中的 OnClick 事件绑定【英文标题】:OnClick Event binding in React.js 【发布时间】:2015-02-08 10:14:24 【问题描述】:

我想在单击该 div 或同一 div 的任何子元素时传递父 div id。但我无法实现它。请告诉我我在哪里犯了错误。代码如下:

viewMore: function(i,j)
        console.log('You clicked: ', i  );
    ,

render : function()
  var attributeId = "groups_";
  attributeId+= index;
  return(
  //parent div
    <div className="groups" id=attributeId onClick=this.viewMore>
        <div className="floatLeft"> Group Name: <h3>My Name</h3></div>
            <span className="floatRight typeCd">POC</span>
        <div className="clearfix"> Key Attributes: 
            <ul>
                <li> POC 1</li>
            </ul>
        </div>
    </div>
    )
;

【问题讨论】:

【参考方案1】:
viewMore = (i,j) => () => 
    console.log(i,j)

要将参数传递给事件处理程序,我们需要使用 currying。 使用上述方法,在调用 render 时不会一直创建新函数。

【讨论】:

^^ 只是.bind(null, attributeId) 这也将在每次重新渲染时运行bind...至少可以说是次优的。 @George Still 会在每次 render 调用时运行 bind。浪费。最优化的方式,IMO,是在构造函数中进行:this.onclick = this.handleClick.bind(this); 然后,在handleClick 中,从 React 事件中检索 attributeIdconst attributeId = event.target 这是一个CodePen 说明该方法。 Zen 是正确的——如果你在组件中使用构造函数,那么渲染方法的污染是不必要的。虽然这个答案有效,甚至可能出现在一些文档示例中,但如果您想最大限度地提高效率,构造函数将更适合您。大多数 React 应用程序的最大问题是渲染方法包含过多的权重,或者在其他情况下未检查触发。【参考方案2】:

由于我在多个地方看到此类建议,我也将把我的评论移到答案中,以提供额外的观点:

class TestComponent extends React.Component 
  constructor() 
    super();
    this.onClick = this.handleClick.bind(this);
  

  handleClick(event) 
    const id = event.target;
    console.log(id);
  

  render() 
    return (
      <div>
        <h3 id=this.props.id onClick=this.onClick>
          this.props.name
        </h3>
      </div>
    );
  

这允许:

    避免不必要的绑定 以更加 React-ive 的方式访问 id 和任何其他属性。

当然,上面的示例假设您收到 id 作为道具,但您也可以进行必要的操作。

更新 1 -- 2016 年 11 月 28 日

从上面的 cmets 添加了到 CodePen 的链接。

更新 2 -- 2017 年 3 月 30 日

如前所述,如果您使用React.createClass 来定义您的组件,这将不起作用。您没有构造函数来完成此操作。如果你不介意有点丑,你可以使用其他生命周期方法。

话虽如此,现在是 2017 年。使用 ES6,好吗?!

更新 3 -- 2017 年 5 月 12 日

如果你使用class properties transform,那么你可以进一步简化它:

class TestComponent extends React.Component 
  onClick = (event) => 
    const id = event.target;
    console.log(id);
  

  render() 
    return (
      <div>
        <h3 id=this.props.id onClick=this.onClick>
          this.props.name
        </h3>
      </div>
    );
  

更新 4 -- 2018 年 2 月 4 日

由于 bind 和 V8 中的朋友(可能还有 Chakra 等)的改进,您最好使用 this.click.bind(this) 或在传递给 onClick 时将其包装在箭头函数中。

为什么?

之前的方法仅出于性能原因而创建,关闭了将函数动态注入组件原型的一些可能性。

注意 1 -- 2018 年 4 月 14 日

请记住,更新 4 中提到的方法仍然引入了一些性能问题,因为在每个 render 传递中,由于 bind 的结果创建了一个新函数。这反过来又会渗透到子组件并导致不必要的重新渲染,因为函数每次都会发生变化。

当您内联传递箭头函数时,也会发生同样的事情。

所有其他方法,比如使用类属性,都会弄乱你的继承(你应该避免,但仍然如此),这仅仅是因为,目前,Babel 将它们转换为“实例”函数,这些函数是不在原型链上。

所以,这个:

class Person 
  printA = () =>  console.log('a') 

变成:

function _classCallCheck(instance, Constructor) ...abridged...

var Person = function Person() 
  _classCallCheck(this, Person);

  this.printA = function () 
    console.log('a');
  ;
;

【讨论】:

这是迄今为止最好的答案,它不仅是一种更有条理的用法,而且它可以防止渲染周期受到污染——更不用说不必要的冗长了。 我使用了类似的方法,但使用了 html5 data-* 属性。处理函数只是做了一个 e.target.attributes['data-XXXX'].value. e.target.dataset.XXXX 会更好,如果这是你的方法。无论如何——以上(在答案中)是 React 对该部分的抽象。 @pikilon“向 JSX 对象添加属性”?那是什么意思?我正在扩展 React 组件的 JS 类上创建一个绑定方法。当然,最好在每次渲染时重新绑定(尽管在 V8 中使用 TurboFan 应该会好得多)。除此之外——这种方式更惯用。 @matanster 你的意思是onClick 作为道具的传递?好吧,我不确定。从render 返回之后,实际的绑定、DOM 和其他东西就会发生。 React 是否每次都重新绑定事件,我不知道。为什么会有这样的担忧?【参考方案3】:

以下是之前答案的更新和概述:

    @HenrikAndersson 使用 onClick=this.viewMore.bind(this, attributeId) .虽然这种方法可以达到目的,但它使用了许多人不习惯的绑定语法。

    使用@ZenMaster提到的public class field。这个解决方案的性能差不多,但语法也更好。但是当我们必须传递一个参数时,它变得很棘手。

    class TestComponent extends React.Component 
      onClick = (event) => 
        const id = event.target;
        console.log(id);
      
    
      render() 
        return (
          <div>
            <h3 id=this.props.id onClick=this.onClick>
              this.props.name
            </h3>
          </div>
        );
      
    
    

上述方法跳过了传递参数,而是使用自定义属性来访问点击处理程序中所需的数据。

更好的解决方案是:

class MyComponent extends React.Component 

    handleClick = (item) => (e) => 
        e.preventDefault()    
        console.log(`This has access to item $item! and event(e)`)
    

    render()
        const item= id:'1', value: 'a' 
        return(
            <button onClick= this.handleClick(item)   >Click</button>
        )
    


参考:Handle events by arrow functions in React app

【讨论】:

【参考方案4】:

你可以使用currying函数。

ES5:

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

    ;

ES6

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

然后像这样使用它:

onClick=this.viewMore("some param")

【讨论】:

这样,在每次渲染时都会调用该方法,而不仅仅是在您单击它时 @Apperside 真实。虽然在大多数情况下这不是问题(如果您指的是性能) 实际上我指的是如果我在 onClick 侦听器中放入一些东西,也许我希望它在我单击它时被执行。这没有任何意义 @Apperside 这里有 2 个方法,一个是您使用参数调用的外部方法,另一个是作为实际事件侦听器返回的方法。这里的诀窍是第二种方法是关闭参数,这将允许您随心所欲地使用它。事件处理程序将仅在触发事件(在本例中为单击)时调用,而不是在您提到的每个渲染时调用。 我明白你的意思,这实际上是有道理的,我仍然想知道这种方法如何影响内存,因为它在每次渲染时都会创建一个新函数......【参考方案5】:

我在这里为 ES6 做了一个更新的答案: https://***.com/a/35748912/76840

本质上,您可以使用箭头函数表达式,它的好处是保留this

onClick=(event)=>this.viewMore(attributeId, event)

截至本次编辑,如果您使用启用了 stage-2 的 Babel,您可以使用如下属性:

// Within your class...
viewMore = (event) =>  /* ... */ 
// Within render method in your JSX
onClick = this.viewMore

【讨论】:

但这不会产生在每次渲染调用时创建一个新函数对象的负面影响吗? @Aaron_H 确实如此,但其他解决方案如.bind 也是如此。在我看来,它是 1) 文档中推荐的方法之一 (facebook.github.io/react/docs/reusable-components.html),2) 至少在我从事的 React 项目中担心函数创建的微优化。如果你想避免这种情况,你可能需要在组件的构造函数中绑定或分配箭头函数,并在 jsx 中传递函数本身... 或者使用 Babel 的 stage-2 的属性,它仍然更干净。

以上是关于React.js 中的 OnClick 事件绑定的主要内容,如果未能解决你的问题,请参考以下文章

React.js 中的 OnClick 事件绑定

如何在react js中的onclick事件上隐藏和显示路由器组件

无法理解react.js中的处理事件[关闭]

事件函数绑定方式

React 事件处理

我是新来的反应。我想在 React JS 中使用 onClick 事件使用单个状态呈现子组件