【问题标题】:OnClick Event binding in React.jsReact.js 中的 OnClick 事件绑定
【发布时间】: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>
    )
};

【问题讨论】:

    标签: javascript reactjs


    【解决方案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>
        );
      }
    }
    

    这允许:

    1. 避免不必要的绑定
    2. 以更加 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】:

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

    1. @HenrikAndersson 使用 onClick={this.viewMore.bind(this, attributeId)} .虽然这种方法可以达到目的,但它使用了许多人不习惯的绑定语法。
    2. 使用@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://stackoverflow.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 的属性,它仍然更干净。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      相关资源
      最近更新 更多