【译】为何我们要写super(props)?
我聽說現在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) {// ? Can’t use `this` yetsuper(props);// ? Now it’s okay thoughthis.state = { isOn: true };}// ... } 復制代碼有一個很好的理由可以解釋為什么JavaScript會強制父構造函數在你訪問this之前運行。考慮一個類層次結構:
class Person {constructor(name) {this.name = name;} }class PolitePerson extends Person {constructor(name) {this.greetColleagues(); // ? This is disallowed, read below whysuper(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);// ? Okay to use `this` nowthis.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(); // ? We forgot to pass propsconsole.log(props); // ? {}console.log(this.props); // ? undefined }// ... } 復制代碼如果在從構造函數調用的某個方法中發生這種情況,調試可能會更加困難。這就是為什么我總是建議大家傳super(props),盡管它不是必需的:
class Button extends React.Component {constructor(props) {super(props); // ? We passed propsconsole.log(props); // ? {}console.log(this.props); // ? {}} } 復制代碼保證在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… by Dan Abramov
轉載于:https://juejin.im/post/5c0f7ca551882516be2f011e
總結
以上是生活随笔為你收集整理的【译】为何我们要写super(props)?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用 Selenium 自动化 web
- 下一篇: 短短30分钟!计算机轻松判断J. K.