【译】React 绑定模式:处理 `this` 的 5 种方式

原文:React Binding Patterns: 5 Approaches for Handling 'this'
说明:因个人水平有限,如有误译,欢迎指正。

JavaScript this 关键字的行为已经让很多开发者困惑不已了。

在 React 中至少有五种方式来处理 this 上下文。现在让我们看一下每一种方式的优劣。

1. 使用 React.createClass

如果您使用的是 React.createClass,React 会将所有的函数绑定到 this 上。因此 this 关键字会自动地绑定到您的组件实例上:

// 使用 React.createClass 很神奇,因为 `this` 已自动为您绑定。
onChange={this.handleChange}

然而,随着 ES6 中类的到来,这种创建类的非标准方式并不是 React 的未来。事实上,createClass 很可能在 React 的未来发行版本中被提取出去。

2. 在 Render 中绑定

接下来的这些方式都假设您是通过 ES6 类的方式来声明 React 组件的。如果您使用了一个 ES6 类,React 将不再为您自动绑定。其中一种方式就是在 render 中调用 bind:

onChange={this.handleChange.bind(this)}

这种方式很简洁,然而,由于函数在每一次渲染的时候都会重新分配,这就带来了性能上的影响。这听起来很重要,但是这种方式所带来的性能影响在大多数应用中并不明显。所以一开始因为性能的原因而将其排除出去是一个不成熟的优化。这里有一个例子会告诉您在什么时候这种方式会带来性能上的影响。

归根结底,如果您有了性能问题,避免在 render 中使用 bind 或箭头函数。

3. 在 Render 中使用箭头函数

这个方式与 #2 类似。您可以在 render 中使用箭头函数从而避免 this 上下文的更改:

onChange={e => this.handleChange(e)}

此方式与 #2 一样,具有潜在的性能影响。

下面可选的方式是值得考虑使用的,因为它们提供了更好的性能,却只需要您额外付出很少的代价。

4. 在构造器中绑定

避免在 render 中绑定的一种方式就是在构造器中绑定(另一种方式是下面讨论的 #5)。

这种方式 目前是 React 文档中推荐的。这也是我在 Pluralsight 视频 “Building Applications with React and Redux in ES6” 中所使用的方式。

然而,在大多数应用中,#2 和 #3 方式的性能影响并不显著,所以 #2 和 #3 方式的可读性和可维护性在多数应用中可能会高于性能方面的考虑。

但是假如您想要使用 stage-2 特性,下面一个选项可能是您最佳的选择。

5. 在类属性中使用箭头函数

这个技术依赖于 提议的类属性特性。想要使用此方式,您必须启用 transform-class-properties 或 stage-2 in Babel。

handleChange = () => {
  // 在 render 中调用此函数
  // 并且 this.whatever 在这里正常执行
};

这个方式具有多个优点:

  1. 箭头函数 在包裹的作用域中采用 this 绑定(换句话说,它们没有改变 this 的含义),所以这些事都会自动完成。
  2. 它避免了方案 #2 和 #3 中的性能问题。
  3. 它避免了方案 #4 中的重复劳动。
  4. 通过将相关的函数转化为箭头函数。它直接将 ES5 createClass 风格重构为现在的风格。事实上,使用 codemod 可以 完全自动化地处理 this。

总结

下面这个流程图对此做了总结。


下面是以上五种方式的示例代码:

// 方案 1:使用 React.createClass
var HelloWorld = React.createClass({
  getInitialState() {
    return { message: 'Hi' };
  },

  logMessage() {
    // this magically works because React.createClass autobinds.
    console.log(this.state.message);
  },

  render() {
    return (
      
    );
  }
});

// 方案 2:在 Render 中绑定
class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hi' };
  }

  logMessage() {
    // This works because of the bind in render below.
    console.log(this.state.message);
  }

  render() {
    return (
      
    );
  }
}

// 方案 3:在 Render 中使用箭头函数
class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hi' };
  }

  logMessage() {
    // This works because of the arrow function in render below.
    console.log(this.state.message);
  }

  render() {
    return (
       this.logMessage()} />
    );
  }
}

// 方案 4:在构造器中使用绑定
class HelloWorld extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hi' };
    this.logMessage = this.logMessage.bind(this);
  }

  logMessage() {
    // This works because of the bind in the constructor above.
    console.log(this.state.message);
  }

  render() {
    return (
      
    );
  }
}

// 方案 5:在类属性中使用箭头函数
class HelloWorld extends React.Component {
  // Note that state is a property,
  // so no constructor is needed in this case.
  state = {
    message: 'Hi'
  };

  logMessage = () => {
    // This works because arrow funcs adopt the this binding of the enclosing scope.
    console.log(this.state.message);
  };

  render() {
    return (
      
    );
  }
}

你可能感兴趣的:(【译】React 绑定模式:处理 `this` 的 5 种方式)