【问题标题】:React performance: anonymous function vs named function vs methodReact 性能:匿名函数 vs 命名函数 vs 方法
【发布时间】:2017-03-03 13:29:16
【问题描述】:

我想知道,在 React.js 中,声明匿名函数、命名函数或组件内的方法之间是否存在性能差异。

具体来说,以下其中一项是否比其他项性能更高?

class MyComponent extends React.Component {
  render() {
    return (
      <input
        type="text"
        value={foo}
        onChange={(e) => {
          this.setState({ foo: e.target.value });
        }}
      />
    );
  }
}

class MyComponent extends React.Component {
  ...
  render() {
    function handleChange(e) {
      this.setState({ foo: e.target.value });
    }
    return (
      <input
        type="text"
        value={foo}
        onChange={handleChange}
      />
    );
  }
}

class MyComponent extends React.Component {
    ...
    handleChange(e) {
      this.setState({ foo: e.target.value });
    }

    render() {
      return (
        <input
          type="text"
          value={foo}
          onChange={this.handleChange}
        />
      );
    }

}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    是的,最肯定的是,你的代码的第三个版本是在 React 组件的 Render 块中引用函数的正确方法。

    为什么?

    对于将被多次调用的方法,嵌套函数通常被认为是一种反模式;这主要是因为 javascript 引擎将函数视为任何其他值,并且必须在父调用完成后创建并随后销毁它。

    如果您需要能够从handleChange() 中访问this,您需要将该方法绑定到组件的上下文。以下是不会对性能产生任何负面影响的方法。

    Vanilla ES6 通过构造函数:

    class MyComponent extends React.Component {
        constructor(props) {
            super(props)
            this.handleChange = this.handleChange.bind(this)
        }
    
        handleChange(e) {
            this.setState({ foo: e.target.value });
        }
    
        render() {
            return (
                <input
                    type="text"
                    value={foo}
                    onChange={this.handleChange}
                />
            )
        }
    }
    

    类属性中的箭头函数(需要带有 transform-class-properties 的 babel):

    class MyComponent extends React.Component {
        handleChange = (e) => {
            this.setState({ foo: e.target.value });
        }
    
        render() {
            return (
                <input
                    type="text"
                    value={foo}
                    onChange={this.handleChange}
                />
            )
        }
    }
    

    装饰类方法(需要带有 transform-decorators-legacy 和 core-decorators 的 babel):

    import { autobind } from 'core-decorators'
    
    class MyComponent extends React.Component {
    
        @autobind
        handleChange(e) {
            this.setState({ foo: e.target.value });
        }
    
        render() {
            return (
                <input
                    type="text"
                    value={foo}
                    onChange={this.handleChange}
                />
            )
        }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 我希望 JavaScript 没有那么混乱
    【解决方案2】:

    第三个选项是最好的。您希望避免在 render 函数中设置状态 setState({}),因为它不再是“纯”的。这是人们在谈论functional programming 时使用的术语。这基本上意味着没有副作用。即使您没有在渲染函数中立即使用 setState 调用这些函数,我认为仍然最好将这个逻辑拉到外面并养成考虑纯函数的习惯。

    Pure Functions 纯函数是一个函数,它: 给定相同的输入,将始终返回相同的输出。 不会产生副作用。 不依赖于外部可变状态。

    同时考虑性能,每次渲染函数运行时,您都会创建一个新函数。您只需要创建一次这些函数,因此最好将它们拉到外面。

    渲染函数多久运行一次?可能很多!每次更改状态或从父组件传递新道具时。

    【讨论】:

    • 我要补充一点,选项 1 和 2 还会在每个渲染上创建一个效率低下的新函数,这就是 OP 正在寻找的原因。
    • 是的,您不需要多次创建这些函数。
    • 所有 3 种渲染方法在函数纯度方面是完全等价的——它们都不是纯的(因为使用了this),并且onChange 属性包含相同类型的值(函数) 在所有 3 种情况下...如果没有适当的绑定(如 Luigi 的回答),第 2 和第 3 选项 甚至无法工作,因此比较性能有点误导
    • 这个答案不正确。正如@Aprillion 所提到的,所有三个示例都是纯函数。第二个示例,使用命名函数甚至不会为handleChange 创建新引用。第一个示例中的匿名函数将在每次渲染时获得一个新的引用。但我相信现代 JavaScript 引擎会倾向于将其优化掉。
    • 谢谢你!我最近了解到这一点,你为我解释了很多
    猜你喜欢
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 2014-05-23
    • 1970-01-01
    • 2011-02-08
    • 2012-12-02
    • 2011-04-20
    相关资源
    最近更新 更多