前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >super(props) 真的那么重要吗?[每日前端夜话0x1F]

super(props) 真的那么重要吗?[每日前端夜话0x1F]

作者头像
疯狂的技术宅
发布2019-03-27 11:09:44
1.3K0
发布2019-03-27 11:09:44
举报
文章被收录于专栏:京程一灯

每日前端夜话0x1F

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:1499 字

预计阅读时间: 7 分钟

翻译:疯狂的技术宅 原文:https://overreacted.io/why-do-we-write-super-props/

我听说 Hooks 最近很火。讽刺的是,我想用一些关于 class 组件的有趣故事来开始这篇文章。你觉得如何?

本文中这些坑对于你正常使用 React 并不是很重要。 但是假如你想更深入的了解它的运作方式,就会发现实际上它们很有趣。

开始第一个。


首先在我的职业生涯中写过的 super(props) 自己都记不清:

当然,在类字段提案 (class fields proposal)【https://github.com/tc39/proposal-class-fields】 中建议让我们跳过这个开头:

在2015年当 React 0.13 增加对普通类的支持时,曾经计划用这样的语法【https://reactjs.org/blog/2015/01/27/react-v0.13.0-beta-1.html#es7-property-initializers】。定义 constructor 和调用 super(props) 始终是一个临时的解决方案,直到类字段能够提供在工程学上不那么反人类的替代方案。

不过还是让我们回到上面这个例子,这次只使用ES2015的特性:

为什么我们要调用super? 可以调用它吗? 如果必须要调用,不传递prop参数会发生什么? 还有其他参数吗? 接下来我们试一试:


在 JavaScript 中,super 指的是父类的构造函数。(在我们的示例中,它指向React.Component的实现。)

重要的是,在调用父类构造函数之前,你不能在构造函数中使用this。 JavaScript 是不会让你这样做的:

为什么 JavaScript 在你使用 this 之前要先强制执行父构造函数,有一个很好的理由能够解释。 先看下面这个类的层次结构:

如果允许在调用 super 之前使用this的话,一段时间后,我们可能会修改 greetColleagues,并在提示消息中添加 Person的 name:

但是我们忘记了 super() 在设置 this.name 之前先调用了 this.greetColleagues()。 所以此时 this.name 还没有定义! 如你所见,像这样的代码很难想到问题出在哪里。

为了避免这类陷阱,JavaScript 强制要求:如果想在构造函数中使用this,你必须首先调用super。 先让父类做完自己的事! 这种限制同样也适用于被定义为类的 React 组件:

这里又给我们留下了另一个问题:为什么要传 props 参数?


你可能认为将props传给super是必要的,这可以使React.Component 的构造函数可以初始化this.props

这与正确答案很接近了 —— 实际上它就是这么做的【https://github.com/facebook/react/blob/1d25aa5787d4e19704c049c3cfa985d3b5190e0d/packages/react/src/ReactBaseClasses.js#L22】。

但是不知道为什么,即便是你调用 super 时没有传递 props 参数,仍然可以在 render 和其他方法中访问this.props。 (不信你可以亲自去试试!)

这是究竟是为什么呢? 事实证明,在调用构造函数后,React也会在实例上分配props

因此,即使你忘记将props传给 super(),React 仍然会在之后设置它们。 这是有原因的。

当 React 添加对类的支持时,它不仅仅增加了对 ES6 类的支持。它的目标是尽可能广泛的支持类抽象。 目前还不清楚【https://reactjs.org/blog/2015/01/27/react-v0.13.0-beta-1.html#other-languages】 ClojureScript、CoffeeScript、ES6、Fable、Scala.js、TypeScript或其他解决方案是如何相对成功地定义组件的。 所以 React 故意不关心是否需要调用 super() —— 即使是ES6类。

那么这是不是就意味着你可以写 super() 而不是super(props)呢?

可能不行,因为它仍然是令人困惑的。 当然,React 稍后会在你的构造函数运行后分配 this.props, 但是在调用 super() 之后和构造函数结束前这段区间内 this.props 仍然是未定义的:

如果这种情况发生在从构造函数调用的某个方法中,可能会给调试工作带来很大的麻烦。 这就是为什么我建议总是调用 super(props) ,即使在没有必要的情况之下:

这样就确保了能够在构造函数结束之前设置好 this.props


最后一点是长期以来 React 用户总是感到好奇的。

你可能已经注意到,当你在类中使用Context API时(无论是旧版的 contextTypes 或在 React 16.6中新添加的 contextType API),context 会作为第二个参数传递给构造函数。

那么为什么我们不写成 super(props, context) 呢? 我们当然可以这样做,但是使用context的频率比较低,所以这个坑并没有那么多影响。

根据类字段提案的说明,这些坑大部分都会消失。 如果没有显式构造函数,则会自动传递所有参数。 这允许在像 state = {} 这样的表达式中包含对 this.propsthis.context 的引用(如果有必要的话)。

而有了 Hooks【https://reactjs.org/docs/hooks-intro.html】 之后,我们甚至不再有 superthis 。 不过这是另外一个的话题了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档