应该如何选择:React.createClass, ES6 Classes, 无状态函数式组件

Shuai Zhang
5 min readDec 29, 2015

--

你已经决定开发一个React组件。你知道它是干什么的,它叫什么,它会变成什么样?但当你打开编辑器开始写第一行代码时,你将面临一个选择,从三种定义组件的方式中选择其一。为什么有三种?应该选择哪一种?

幸运的是,这不是一个难做的决定。事实上,结合一点历史和两条简单的原则,你只需要花费几秒中就能继续开发你的组件。不多介绍了,这是第一条原则:

原则1:如果你的组件需要访问“this”就用ES6 Classes

无状态函数无法访问“this”对象;如果你需要访问定义在“this”对象,而不是“props”中的属性,你需要一个组件类。

但“this.state”和“this.refs”是很多实用的React组件必不可少的。做这样的限制是不是有些奇怪?

为什么无状态函数组件不能有“this”?

如你所知,JSX标签会被编译成原生的JavaScript对象,而不是HTML。

以“<div />”标签为例。经过JSX编译器编译后我们得到:

React.createElement('div')

如React文档显示,这行代码只返回一个“ReactElement” ——一个原生js对象。“ReactElement”的结构可能如下:

{ type: 'div', props: {}, ref: null, key: null }

这显示了一个有趣的问题:如果每次调用组件的“render”函数都产生一个新的对象,那么在每次渲染后,组件的“this”对象是如何一直包含相同的“state”和“refs的?更进一步,纯JavaScript对象是如何连接到DOM的?

React元素和类实例

好吧,我承认上面内容有些故弄玄虚。我故意略去了重要的一步。

还记得通过“<div />”创建的那个“ReactElement”吗?它并没有连接到DOM。直到你调用“ReactDOM.render”把它和它的子节点渲染到DOM中,它才会连接到DOM。“ReactDOM.render”不只创建了DOM节点——它还创建了“ReactComponent”的实例。

但“ReactComponent”的实例是什么?可以这样理解:如果“ReactElement”相当于一条指令,通知React,你需要一个你的组件的实例。“ReactComponent”的实例才是真正的组件。或者换一种方式表达,渲染“ReactElement”,是在通知React,我们需要一个“ReactComponent”。

让我们做一个简单的测试来验证你是否理解了这些。基于上面的解释,你知道你的组件的“this”是什么类型的对象吗?(直接贴答案,这个编辑器不支持隐藏答案)

“this”是一个“ReactComponent”实例。每个实例拥有自己的“state”,“refs”等等。

无状态的函数组件

无状态的函数组件不是类 ——他们是函数。他们没有连接到“ReactComponent”实例的“this”属性。虽然“this”对象扩展了组件的可能性,但它也付出了代价——保持“ReactComponent”和“ReactElement”对象的链接需要付出额外的工作。

使用无状态的函数组件,相当于在通知React,你不需要那个“ReactComponent”。基于这一点,可以做大量的优化——目前仍在持续增长。即使在这些性能提升完还没完成,使用无状态函数,你的组件依然可以少做很多事情。由此引入第二条原则:

原则2:如果你的组件需要生命周期方法,使用ES6 Classes

没有“this”属性,无状态函数组件是无法访问他们的生命周期方法的。

也许你已经注意到,上面两条原则有相同之处:他们都是关于在哪些场景下无状态函数组件不能被使用。于是,你不需要两条规则,他们可以被合并为:

黄金原则:如果你能够使用无状态函数组件,那就用吧

当然,有些时候你无法使用无状态的函数组件。这些场景下,我建议用“React.Component”,不用“React.createClass”。至于为什么,让我们了解一点历史。

一点历史

你可能已经知道,React是近期才支持无状态函数组件的。这就解释了,为什么即便可以,你也不想使用无状态函数——如果没有一个清晰原因,他们也不会被添加。

你可能也已经知道,React.Component 也是最近才支持的。这是一个线索,表明相比“React.createClass”,“React.Component”更被推荐使用。另一个线索,看看他们所在代码仓库目录的名字吧——“modern”和“classic”。

更具体的,“React.Component”比“React.createClass”有更简单的API。

简单、同样强大的API

“React.createClass”拥有mixins,ES6 Classes非常适合高阶函数(Higher Order Components — HOC)。对于高阶函数,一开始你可能感觉不熟悉,但很快他们比mixins更自然。HOC以更直观的形式,展示了比mixins更强大的功能。并且,HOC是纯净的javascript,你不用担心他们会被废弃。

同样,“React.createClass”有自绑定的函数方法,Babel和ES6 Classes让你只绑定需要的方法。这会提高性能,同时降低你的代码过时的可能性。

现在,你知道该如何定义你的组件了。总结下:

  • 如果可以可以用无状态函数,尽管用
  • 否则,用 ES6 Classes

--

--