热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

props写法_【译】我们为什么要写super(props)?

原文地址:WhyDoWeWritesuper(props)?原文作者:DanAbramov译者:WashingtonHua我听说Hooks
3dc05838e72e5edcae428d2a8092840e.png
原文地址:Why Do We Write super(props) ?
原文作者:Dan Abramov
译者:Washington Hua

我听说 Hooks 最近很火。讽刺的是,我想以一些关于 class 组件的有趣故事来开始这个博客。怎样!(皮一下很开心)

这些小坑并不会影响你高效的使用 React,但如果你愿意深入了解下背后的工作原理,你会发现它们非常有意思。

这是第一个。


我这辈子写过的 super(props) 比我想象的要多得多

class Checkbox extends React.Component {constructor(props) {super(props);this.state = { isOn: true };}// ...
}

当然,class fields proposal 允许我们跳过这个仪式。

class Checkbox extends React.Component {state = { isOn: true };// ...
}

这样的语法是在 2015 年 React 0.13 增加对纯 Class 的支持的时候加入 计划 的. 定义 constructor 和调用 super(props) 一直都只是 class fiels 出现之前的临时解决方案。

然而,让我们只用 ES2015 的特性来回顾一下这个例子。

class Checkbox extends React.Component {constructor(props) {super(props);this.state = { isOn: true };}// ...
}

我们为什么要调用super?能不能不调用它?如果非要调用,如果不传 props 会怎样?还有其它参数吗?让我们来看一下。

在 Javascript 中,super 指代父类的构造函数。(在我们的案例中,它指向 React.Component 这个实现)

重点在于,在你调用父类构造函数之前,你无法在构造函数中使用 this。Javascript 不会允许你这么做。

class Checkbox extends React.Component {constructor(props) {// 这时候还不能使用 `this`super(props);// ✅ 现在开始可以了this.state = { isOn: true };}// ...
}

Javascript 强制你在使用 this 前运行父类构造函数有一个很好的理由。考虑这样一个类结构:

class Person {constructor(name) {this.name = name;}
}class PolitePerson extends Person {constructor(name) {this.greetColleagues(); // 这是不允许的,下面会解释原因super(name);}greetColleagues() {alert('Good morning folks!');}
}

想象一下如果在调用 super 前使用 this 是被允许的。一个月之后。我们或许会改变 greetColleagues 把 person 的 name 加到消息中。

greetColleagues() {alert('Good morning folks!');alert('My name is ' + this.name + ', nice to meet you!');
}

但我们忘了 this.greetColleagues() 是在 super() 有机会设置 this.name 之前被调用的。this.name 甚至还没被定义!如你所见,像这样的代码理解起来会很困难。

为了避免这样的陷阱,Javascript 强制规定,如果你想在构造函数中只用this,就必须先调用 super。让父类做它该做的事!这一限制也适用于定义成类的 React 组件。

constructor(props) {super(props);// ✅ 现在可以使用 `this` 了this.state = { isOn: true };
}

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


你或许觉得把 props 传进 super 是必要的,这使得基类 React.Component 可以初始化 this.props:

// React 内部
class Component {constructor(props) {this.props = props;// ...}
}

很接近了——事实上,它就是这么做的。

然而,即便在调用 super() 时没有传入 props 参数,你依然能够在 render 和其它方法中访问 this.props。(你要是不相信我,可以自己试一试)

这是什么原理?其实 React 在调用你的构造函数之后,马上又给实例设置了一遍 props:

// React 内部
const instance = new YourComponent(props);
instance.props = props;

因此,即便你忘了把 props 传入 super(),React 依然会在事后设置它们。这是有理由的。

当 React 添加对 Class 的支持时,它并不是只添加了对 ES6 的支持,而是希望能够支持尽可能广泛的 class 抽象。由于不是很确定 ClojureScript、CoffeeScript、ES6、Fable、Scala.js、TypeScript 或其他解决方案谁更适合用来定义组件,React 对于是否有必要调用 super() 刻意不表态。

那么这是否意味着你可以只写 super() 而不用 super(props)?

或许并非如此,因为这依然让人困扰。诚然,React 会在你的构造函数运行之后设置 this.props。但在 super 调用一直到构造函数结束之前,this.props 依然是未定义的。

// React 内部
class Component {constructor(props) {this.props = props;// ...}
}// 你的代码
class Button extends React.Component {constructor(props) {super(); // 我们忘了传入 propsconsole.log(props); // ✅ {}console.log(this.props); // undefined }// ...
}

如果这发生在某些从构造函数中调用的函数,调试起来会更加麻烦。这也是为什么我推荐总是使用 super(props) 的写法,即便这是非必要的:

class Button extends React.Component {constructor(props) {super(props); // ✅ 我们传了 propsconsole.log(props); // ✅ {}console.log(this.props); // ✅ {}}// ...
}

这样的写法确保了 this.props即便在构造函数返回之前就被设置好了。


最后还有一点是 React 的长期用户或许会好奇的。

你或许已经注意到,当你在 Class 中使用 Context API 时(无论是旧版的语法还是 React 16.6 中新增的现代化语法),context 是被作为构造函数的第二个参数传入的。

那么我们为什么不写 super(props, context) 呢?当然我们可以这么做,但 context 的使用频率没那么高,所以这个陷阱影响还没那么大。

伴随着 class fields proposal 的发布,这个问题也就不复存在了。即便不显式调用构造函数,所有参数也会自动传入。这就允许像 state = {} 这样的表达式在必要时可以直接引用 this.props.this.context

在 Hooks 中,我们甚至都没有 superthis。这个话题我们择日再说。



推荐阅读
  • 小编给大家分享一下TypeScript2.7有什么改进,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 前言小伙伴们大家好。从今天开始我们将从 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
  • 本文介绍了自学Vue的第01天的内容,包括学习目标、学习资料的收集和学习方法的选择。作者解释了为什么要学习Vue以及选择Vue的原因,包括完善的中文文档、较低的学习曲线、使用人数众多等。作者还列举了自己选择的学习资料,包括全新vue2.5核心技术全方位讲解+实战精讲教程、全新vue2.5项目实战全家桶单页面仿京东电商等。最后,作者提出了学习方法,包括简单的入门课程和实战课程。 ... [详细]
  • 枚举使用枚举我们可以定义一些带名字的常量。使用枚举可以清晰地表达意图或创建一组有区别的用例。TypeScript支持数字的和基于字符串的枚举。数字枚举首先我们看看数字枚举,如果你使 ... [详细]
  • TS-入门学习笔记TypeScript是JavaScript的一个超集,主要提供了类型系统和对ES6的支持。与js相比,最大的有点是类型系统的引入,由于js本身是弱类型语言,所以天 ... [详细]
  • 我试图在Angular2应用程序中使用元素调整大小检测器库(https:github.comwnrelement-resize-detector).根据我有限的JS模块知识,该库似 ... [详细]
  • 刘连响:为什么看好小程序音视频在教育行业的应用?
    作者简介:刘连响,一起玩耍科技创始人。2013年起开始研究WebRTC,对音视频处理、直播、实时音视频相关技术非常感兴趣,具 ... [详细]
author-avatar
尼姆了_960
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有