【译】为何我们要写super(props)?
栏目: JavaScript · 发布时间: 5年前
内容简介:我听说现在Hooks是新的热点。讽刺地是,我想描述类的相关事实作为这片博客的开始。那是怎么样的呢?这些坑对于有效地使用React并不重要。但如果你想更深入地了解事物的工作原理,你可能会发现它们很有趣。这是第一个。
我听说现在Hooks是新的热点。讽刺地是,我想描述类的相关事实作为这片博客的开始。那是怎么样的呢?
这些坑对于有效地使用React并不重要。但如果你想更深入地了解事物的工作原理,你可能会发现它们很有趣。
这是第一个。
我的生命中我写的 super(props)
在我的生命中我写的 super(props)
比我知道的多:
class Checkbox extends React.Component { constructor(props) { super(props); this.state = { isOn: true }; } } // ... 复制代码
当然, 类相关的提议 让我们跳过了这个仪式:
class Checkbox extends React.Component { state = { isOn: true }; // ... } 复制代码
2015年React 0.13增加了对纯类的支持时,就计划了这样的语法。定义 constructor
函数和调用 super(props)
一直是一种临时解决方案,直到类字段提供了一种符合人体工程学的替代方案。
但是让我们回到这个例子,只使用ES2015特性:
class Checkbox extends React.Component { construtor(props) { super(props); this.state = { isOn: true }; } // ... } 复制代码
为何我们要调用 super
?我们可以不调用它吗?如果我们不得不调用它,不传 props
参数会发生什么呢?还存在其它的参数吗? 让我们一探究竟。
为何我们要调用 super?调用不当会发生什么呢?
在JavaScript中, super
引用的是父类的 constructor
(在我们的例子中,它指向 React.Component
实现)。
重要的是,你不能使用 this
直到你调用父级的 constructor
后。JavaScript不会让你那样做:
class Checkbox extends React.Component { constructor(props) { // :red_circle: Can’t use `this` yet super(props); // :white_check_mark: Now it’s okay though this.state = { isOn: true }; } // ... } 复制代码
有一个很好的理由可以解释为什么JavaScript会强制父构造函数在你访问 this
之前运行。考虑一个类层次结构:
class Person { constructor(name) { this.name = name; } } class PolitePerson extends Person { constructor(name) { this.greetColleagues(); // :red_circle: This is disallowed, read below why super(name); } greetColleagues() { alert('Good morning forks!'); } } 复制代码
想象一下 this
在 super
之前被调用是被允许的。一个月后,我们可能改变 greetColleagues
中包含在person中的信息:
greetColleagues() { alert('Good morning folks!'); alert('My name is ' + this.name + ', nice to meet you!'); } 复制代码
但是我们忘记了 super()
在有机会设置 this.name
之前调用了 this.greetemployees()
,因此 this.name
都还没定义。正如你所看到的一样,很难思考像这样的代码。
为了避免这样的坑,
JavaScript会迫使你在使用 this
之前先调用 super
.
让父级做它该做的事情!这个限制也适用于定义为类的React组件:
construtor(props) { super(props); // :white_check_mark: Okay to use `this` now this.state = { isOn: true }; } 复制代码
这里还存在另外一个问题:为什么要传递 props
?
你也许认为传递 props
给 super
是必要的,这样 React.Component
构造函数就能初始化 this.props
了:
// Inside React class Component { constructor(props) { this.props = props; // ... } } 复制代码
这与事实相去不远——确实, 事实就是如此 。
但是,即使你调用 super
没带 props
参数,你依然可以在 render
或者其它方法中获取到 props
。(如果你不信我,你可以自己试试!)
那到底是怎样工作的呢?事实表明
React
也会在调用构造函数后立即在实例上初始化 props
:
// Inside React const instance = new YourComponent(props); instance.props = props; 复制代码
因此即使你忘记了给 super
传递 props
, React
也会立即设置它们。这是有原因的。
当React添加了对类的支持时,它不仅仅只支持ES6中的类。目标是支持尽可能广泛的类抽象。目前还不清楚使用 ClojureScript
, CoffeeScript
, ES6
, Fable
, Scala.js
, TypeScript
,或者其它方式定义组件会有多成功。因此,React故意不明确是否需要调用 super()
——即使ES6的类需要。
所以这就意味着你可以使用 super()
代替 super(props)
了吗?
可能不是因为它仍然令人困惑。当然,React会在你运行了 constructor
之后为 this.props
赋值。但是在 super
调用和构造函数结束之间, this.props
仍然是未定义的:
// Inside React class Component { construtor(props) { this.props = props; // ... } } // Inside your code class Button extends React.Component { constructor(props) { super(); // :grimacing: We forgot to pass props console.log(props); // :white_check_mark: {} console.log(this.props); // :grimacing: undefined } // ... } 复制代码
如果在从构造函数调用的某个方法中发生这种情况,调试可能会更加困难。
这就是为什么我总是建议大家传 super(props)
,尽管它不是必需的:
class Button extends React.Component { constructor(props) { super(props); // :white_check_mark: We passed props console.log(props); // :white_check_mark: {} console.log(this.props); // :white_check_mark: {} } } 复制代码
保证在 constructor
存在之前 this.props
就被设置了。
还有最后一点React用户可能会感到好奇的。
你可能注意到在类中使用 Context API
时(包括旧的 contextTypes
和在 React16.6
中添加的现代 contextType API
), context
作为第二个参数被传给 constructor
。
为什么我们不用 super(props, context)
代替呢?我们能够,只是上下文的使用频率较低,所以这个坑不会经常出现。
随着类字段的提议,这个坑基本上消失了。如果没有显式构造函数,所有参数都将被自动传递下去。这就是允许像 state ={}
这样的表达式包含对 this.props
或者 this.context
的引用的原因。
使用 Hooks
,我们甚至不会使用到 super
或者 this
。但是那是下次的话题。
原文链接: overreacted.io/why-do-we-w… byDan Abramov
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。