React.js 中的 OnClick 事件绑定

IT技术 javascript reactjs
2021-02-09 02:04:25

我想通过div单击该 div 或相同div. 但我无法实现它。请告诉我我哪里出错了。代码如下:

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>
    )
};
5个回答
viewMore = (i,j) => () => {
    console.log(i,j)
}

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

Zen 是正确的 - 如果您在组件中使用构造函数,则不需要渲染方法的污染。虽然这个答案有效,甚至可能出现在一些文档示例中,但如果您想最大限度地提高效率,构造函数将更适合您。大多数 React 应用程序的最大问题是渲染方法包含过多的权重,或者在其他情况下未经检查就触发。
2021-03-23 02:04:25
@George 仍然会bind在每次render通话时运行浪费。IMO 的最佳方法是在构造函数中执行此操作:this.onclick = this.handleClick.bind(this); 然后,在 中handleClickattributeId从 React 事件中检索const {attributeId} = event.target
2021-03-25 02:04:25
这也将bind在每次重新渲染时运行......至少可以说这是次优的。
2021-04-05 02:04:25
这是一个说明该方法CodePen
2021-04-08 02:04:25
^^ 只是 .bind(null, attributeId)
2021-04-13 02:04:25

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

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

这允许:

  1. 避免不必要的绑定
  2. id以更具react性的方式访问 the和其他任何属性。

当然,上面的例子假设你收到了id一个 prop,但你也可以做一些必要的操作。

更新 1 -- 2016 年 11 月 28 日

添加了来自上述评论的CodePen链接

更新 2 -- 2017 年 3 月 30 日

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

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

更新 3 -- 2017 年 5 月 12 日

如果您使用的是类属性 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 日

由于bindV8 中和朋友的改进(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');
  };
};
e.target.dataset.XXXX会更好,如果这是你的方法。无论如何——以上(在答案中)是 React 对该部分的抽象。
2021-03-17 02:04:25
这是迄今为止最好的答案,它不仅是一种更有条理的用法,而且可以防止渲染周期受到污染 - 更不用说不必要的冗长了。
2021-03-19 02:04:25
@pikilon“向 JSX 对象添加属性”?这意味着什么?我正在一个扩展 React 组件的 JS 类上创建一个方法,一个绑定的方法。当然,最好在每次渲染时重新绑定(尽管在 V8 中使用 TurboFan 应该会好得多)。除此之外 - 这样更惯用。
2021-03-23 02:04:25
@matanster 你的意思是onClick作为道具传递好吧,我不确定。实际的绑定,DOM 和其他东西,发生在你从render. React 是否每次都重新绑定事件,我不知道。为什么会有这种担忧?
2021-03-24 02:04:25
我使用了类似的方法,但使用了 HTML5 data-* 属性。处理函数只是做了一个 e.target.attributes['data-XXXX'].value。
2021-04-11 02:04:25

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

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

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

在此编辑中,如果您使用启用了第 2 阶段的 Babel,您可以使用如下属性:

// Within your class...
viewMore = (event) => { /* ... */ }
// Within render method in your JSX
onClick = {this.viewMore}
但这不是在每次渲染调用时创建新函数对象的负面影响吗?
2021-03-24 02:04:25
或者使用 Babel 的 stage-2 中的属性,它仍然更干净。
2021-03-28 02:04:25
@Aaron_H 确实如此,但其他解决方案(如.bind. 在我看来,它是 1) 文档中推荐的方法之一 ( facebook.github.io/react/docs/reusable-components.html),2 ) 微优化,至少在我参与过的 React 项目。如果您想避免这种情况,您可能需要在组件的构造函数中绑定或分配箭头函数,并在 jsx 中传递函数本身...
2021-04-12 02:04:25

您可以使用柯里化功能。

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")}
通过这种方式,该方法在每次渲染时都会被调用,而不仅仅是在您单击它时
2021-03-15 02:04:25
@Apperside 是真的。尽管在大多数情况下这不是问题(如果您指的是性能)
2021-03-20 02:04:25
@Apperside 这里有 2 个方法,一个是你用参数调用的外部方法,另一个是作为实际事件侦听器返回的方法。这里的技巧是第二种方法关闭参数,这将允许您随心所欲地使用它。事件处理程序只会在事件被触发时被调用(在这种情况下是单击),而不是像您提到的那样在每次渲染时被调用。
2021-03-29 02:04:25
实际上,我指的是这样一个事实:如果我将某些内容放入 onClick 侦听器中,也许我希望在单击它时执行它。那没有任何意义
2021-04-07 02:04:25
我明白你的意思,它实际上是有道理的,我仍然想知道这种方法如何影响内存,因为它在每次渲染时都创建了一个新函数......
2021-04-12 02:04:25

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

  1. 通过使用的onClick = {this.viewMore.bind(此,属性Id)} @HenrikAndersson 。而这种方法提供它使用的绑定的语法与许多不舒服的目的。
  2. 使用@ZenMaster提到的公共类字段。这个解决方案或多或少具有相同的性能,它还带有更好的语法。但是当我们必须传递一个参数时就变得很棘手了。

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

}

参考:在 React 应用中通过箭头函数处理事件