Javascript React,为每个事件绑定一个新函数的有效性

Javascript React,为每个事件绑定一个新函数的有效性,javascript,reactjs,dom-events,Javascript,Reactjs,Dom Events,我的朋友和我在争论。为了充分披露,我是React及其好处的忠实粉丝 在React components中,当将DOM事件附加到元素列表中的每个元素时,传统的模式是bind()generic click处理程序,其中包含要作为参数传递给该函数的值。如下文所述: <button onClick={this.onButtonClick.bind(this, buttonIndex)}></button> 我的朋友认为这种做事方式效率极低。这需要创建一个新函数并保存在内存中,以

我的朋友和我在争论。为了充分披露,我是React及其好处的忠实粉丝

在React components中,当将DOM事件附加到元素列表中的每个元素时,传统的模式是
bind()
generic click处理程序,其中包含要作为参数传递给该函数的值。如下文所述:

<button onClick={this.onButtonClick.bind(this, buttonIndex)}></button>
我的朋友认为这种做事方式效率极低。这需要创建一个新函数并保存在内存中,以处理每个按钮的事件。我同意他的观点,但我觉得如果库不能有效地处理事件及其处理程序,React开发人员不会鼓励这种模式

他用来避免这种情况的模式是使用
data-
属性并从DOM元素本身获取值(在本例中为
buttonIndex
):

<button data-buttonIndex={buttonIndex} onClick={this.onButtonClick}></button>
再一次,我有偏见,因为我是React的粉丝。但这感觉不对,原因有二:

  • 从DOM中获取值来传递数据(如state)在很多方面都有点违背了React的目的,对吧
  • 数据-
    属性在我看来非常模糊。它们可以从几个不同的地方设置(HTML、JS、PHP等)。他们也没有暗示任何隐含的目的。“数据”可以在任何地方使用(JS、CSS等)

  • React做了一些特殊的魔法来提高DOM事件的效率吗?如果没有,是否有一种替代模式不使用
    data-
    属性,并且更明确地说明它的用法?

    我认为在一般情况下,直接在
    render
    中绑定函数是惯用的方式,因为它们在文档中执行,正如您所指出的,并且根据我们的经验,性能并没有显著降低。但是,在某些情况下,您不希望在每次渲染时重新绑定函数,例如,如果您正在比较
    shouldComponentUpdate
    中的道具(如
    PureRenderMixin
    )。要按照您朋友的建议做一些非常类似的事情,但不使用jQuery查看DOM(我相信这是一种常见的模式),您可以将索引作为道具传递

    class Parent extends React.Component {
      render() {
        return [...some array].map((item, index) => {
          return <Child item={item} index={index} />;
        });
      }
    }
    
    class Child extends React.Component {
      constructor() {
        super();
        this.handleClickButton = this.handleClickButton.bind(this);
      }
    
      handleClickButton() {
        // use this.props.index here
      }
    
      render() {
        return <button onClick={this.handleClickButton}></button>;
      }
    }
    
    类父级扩展React.Component{
    render(){
    返回[…某些数组].map((项,索引)=>{
    返回;
    });
    }
    }
    子类扩展了React.Component{
    构造函数(){
    超级();
    this.handleClickButton=this.handleClickButton.bind(this);
    }
    handleClickButton(){
    //在此处使用this.props.index
    }
    render(){
    返回;
    }
    }
    

    注意:当使用ES6类时,您需要在构造函数中手动绑定到
    this
    ,因为您正在访问
    this.props
    。如果使用的是
    React.createClass
    ,则不需要这样做

    我不确定这是个好主意,但是。。。回忆录

    class Foo {
      constructor(){
        this.getClickHandler = _.memoize(this.getClickHandler);
      }
    
      getClickHandler(index){
        return (event) => {
          doSomething();
        };
      }
    
      render(){
        // ...
           <button onClick={this.getClickHandler(index)}>Click me</button>
        // ...
      }
    }
    
    class-Foo{
    构造函数(){
    this.getClickHandler=\ u0.memoize(this.getClickHandler);
    }
    getClickHandler(索引){
    返回(事件)=>{
    doSomething();
    };
    }
    render(){
    // ...
    点击我
    // ...
    }
    }
    
    这样可以避免创建新函数,避免数据属性,并避免在dom中查找任何内容的性能成本



    我不认为我曾经分析过,并发现在渲染中创建函数是一个问题。这绝对是你应该优化的东西,只有当数字告诉你这样做。

    我很想听到关于这方面的评论。我的看法:“极度”低效?你有多少个按钮<代码>数据-属性“不明确”?他们隐含的目的是。。。传递数据。是的,数据可以在任何地方使用,这对我来说并不是天生的坏,因为你可能想从其他地方使用它<代码>绑定创建一个新函数;无论他们如何处理,React对此无能为力,除非他们编写了自己的绑定。这是内存和易用性之间的折衷。作为一个补充,使用ES6,您现在可以避免讨厌的
    绑定
    ,而是使用箭头函数:
    this.onButtonClick(buttonIndex)}>
    @DaveNewton在表的每一行中都有按钮,表可能有数百行长。您的朋友确定
    bind
    会导致整个函数在内存中重复吗?我认为JavaScript实现人员应该足够聪明,可以将绑定函数存储为对原始函数的引用,以及绑定的
    this
    对象和参数。我想不出函数本身会被复制的原因,但我很想听听你朋友的相反推理。
    class Parent extends React.Component {
      render() {
        return [...some array].map((item, index) => {
          return <Child item={item} index={index} />;
        });
      }
    }
    
    class Child extends React.Component {
      constructor() {
        super();
        this.handleClickButton = this.handleClickButton.bind(this);
      }
    
      handleClickButton() {
        // use this.props.index here
      }
    
      render() {
        return <button onClick={this.handleClickButton}></button>;
      }
    }
    
    class Foo {
      constructor(){
        this.getClickHandler = _.memoize(this.getClickHandler);
      }
    
      getClickHandler(index){
        return (event) => {
          doSomething();
        };
      }
    
      render(){
        // ...
           <button onClick={this.getClickHandler(index)}>Click me</button>
        // ...
      }
    }