反应生命周期方法的类属性

时间:2018-01-12 20:15:29

标签: javascript reactjs babeljs

我可以将React生命周期方法编写为类属性吗?

我一直在使用类属性,因为我喜欢不再需要手动绑定我的方法这一事实,但我希望在我的组件之间保持一定的一致性。我想知道将React生命周期方法编写为类属性

是否有任何缺陷
import React, { Component } from 'react';

class MyComponent extends Component {

  render = () => {
    return (
      <div>Foo Bar</div>
    );
  }

}

export default MyComponent;

例如,与等效方法中的上下文相比,此类属性的上下文是否受到影响。鉴于上述代码中的render方法被写为箭头函数,这种关注似乎是相关的。

2 个答案:

答案 0 :(得分:5)

在某种程度上,真正的答案取决于您的构建管道以及生成的Javascript输出的外观。主要有两种可能性:

输入代码

让我们首先说你在进行任何类型的管道转换(babel,打字稿等)之前写下以下内容:

class Test {
    test = () => { console.log('test'); };
}

输出为类成员变量。

在一个可能的世界中,您的管道也将输出test函数作为输出类的成员变量。在这种情况下,输出可能类似于:

function Test() {
    this.test = function() { console.log('test'); };
}

这意味着每当您编写new Test()时,每次都会重新创建test函数。

输出为类原型函数

在另一个主要的可能性中,您的管道可能会将其识别为函数属性,并将其从类实例转义为原型。在这种情况下,输出可能类似于:

function Test() {
}

Test.prototype = {
    test: function() { console.log('test'); }
}

这意味着无论您拨打new Test()多少次,内存中仍然只会创建一个test函数。

期望的行为

希望很明显,你希望你的最终结果让函数最终在原型对象上,而不是在每个类实例上重新创建。

但是,虽然您希望函数不会以属性结束,但这并不一定意味着您无法在自己的代码中以这种方式编写它。只要您的构建链正在进行正确的转换,您就可以按照自己喜欢的方式编写它。

虽然,查看默认的babel设置(你的babeljs标签让我相信你正在使用它),但它并没有为你做这个转换。您可以在行动here中看到这一点。在左边,我创建了一个类,其中函数作为属性,一个类将函数作为类方法。在右侧,babel显示它的输出,您可以看到具有该属性的类仍然具有实例级属性,这意味着每次调用该类的构造函数时都会重新创建它。

我确实找到了this babel plugin,这似乎可能会增加这种转变,但我并没有将它用于自己,所以我不是肯定的。

答案 1 :(得分:2)

根据我的经验,将方法编写为类属性的最大原因是该方法将作为回调传递,并且您需要将其始终绑定到实例。 React生命周期方法将始终作为方法调用,因此没有理由将它们绑定(并且当你这样做时会产生微小的内存损失)。这会产生影响的是当您将函数作为回调传递给组件时(例如onClickonChange)。

举个例子:

class BrokenFoo extends React.Component {
    handleClick() {
        alert(this.props.message);
    }

    render() {
        return (
            <button onClick={this.handleClick}>
                Click me
            </button>
        )
    }
}

this.handleClick表示的函数不会自动绑定到组件实例,因此当方法尝试读取this.props的值时,它会抛出TypeError,因为this } 没有定义。如果您不熟悉this,请阅读this article;第4.2节“陷阱:不正确地提取方法”中描述的问题基本上是在传递方法时发生的事情而不确定它是否正确绑定。

这是类,用处理程序作为类属性重写:

class HappyFoo extends React.Component {
    handleClick = () => {
        alert(this.props.message);
    }

    render() {
        return (
            <button onClick={this.handleClick}>
                Click me
            </button>
        )
    }
}

实际上,您可以将第二个示例中的handleClick定义视为将此代码放入组件的构造函数中(这与Babel完全相同):

this.handleClick = () => {
    alert(this.props.message);
}

这与在函数上调用bind实现相同的功能(如链接文章中所述),但执行方式略有不同。因为此函数是在构造函数中定义的,所以this中的this.props.message的值绑定到包含的实例。这意味着该函数现在独立于调用上下文;你可以传递它,它不会破裂。

我遵循的经验法则:默认情况下,将方法写为方法。这会将方法附加到prototype,并且通常会按照您期望的方式运行。但是,如果该方法是在没有括号的情况下编写的(即您传递了值而没有调用它),那么您可能希望将其设为类属性。