為什么要寫super(props)

原文: Why Do We Write super(props)?

本文原文: 為什么寫render(props)

我聽說hooks最近很熱。具有諷刺意味的是,我想通過描述有關(guān)類組件的有趣事實(shí)來開始這個(gè)博客。那會(huì)怎么樣!

這些陷阱對(duì)于有效地使用React并不重要。但是如果你想更深入地了解事情的運(yùn)作方式,你可能會(huì)發(fā)現(xiàn)它們很有趣。

這是第一個(gè)。


我寫過的super(props)比我知道的要多:

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

當(dāng)然,類字段提案讓我們跳過儀式:

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

當(dāng)React 0.132015年增加對(duì)普通類的支持時(shí),計(jì)劃使用這樣的語(yǔ)法。定義構(gòu)造函數(shù)和調(diào)用super(props)成為臨時(shí)解決方案,直到類字段提供符合人體工程學(xué)的替代方案。

但是,讓我們回到這個(gè)例子,只使用ES2015功能:

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

我們?yōu)槭裁凑{(diào)用super?我們可以不調(diào)用它嗎?如果我們必須調(diào)用它,如果我們不傳遞props會(huì)發(fā)生什么?還有其他論點(diǎn)嗎?讓我們來看看。

在JavaScript中,super指的是父類構(gòu)造函數(shù)。(在我們的示例中,它指向React.Component實(shí)現(xiàn)。)

重要的是,在調(diào)用父構(gòu)造函數(shù)之前,不能在構(gòu)造函數(shù)中使用this。 JavaScript不會(huì)讓你:

class Checkbox extends React.Component {
  constructor(props) {
    // ?? Can’t use `this` yet
    super(props);
    // ? Now it’s okay though
    this.state = { isOn: true };
  }
  // ...
}

有一個(gè)很好的理由說明為什么JavaScript在你觸摸它之前強(qiáng)制執(zhí)行父構(gòu)造函數(shù)??紤]一個(gè)類層次結(jié)構(gòu):

class Person {
  constructor(name) {
    this.name = name;
  }
}

class PolitePerson extends Person {
  constructor(name) {
    this.greetColleagues(); // ?? This is disallowed, read below why
    super(name);
  }
  greetColleagues() {
    alert('Good morning folks!');
  }
}

想象一下,在允許調(diào)用super之前使用this。一個(gè)月后,我們可能會(huì)更改greetColleagues以在郵件中包含此人的姓名:

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

但是我們忘記了在super調(diào)用有機(jī)會(huì)設(shè)置this.name之前調(diào)用this.greetColleagues。所以this.name甚至還沒有定義!如您所見,這樣的代碼很難想到。

為了避免這些陷阱,JavaScript強(qiáng)制要求如果你想在構(gòu)造函數(shù)中使用它,你必須首先調(diào)用super。讓父級(jí)做自己的事!此限制也適用于定義為類的React組件:

constructor(props) {
    super(props);
    // ? Okay to use `this` now
    this.state = { isOn: true };
  }

這給我們留下了另一個(gè)問題:為什么要傳遞props?


你可能認(rèn)為將props傳遞給super是必要的,以便基本的React.Component構(gòu)造函數(shù)可以初始化this.props

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

這與事實(shí)并不遙遠(yuǎn) - 事實(shí)上,這就是它的作用。

但不知何故,即使你沒有使用props參數(shù)調(diào)用super,你仍然可以在render和其他方法中訪問this.props。 (如果你不相信我,請(qǐng)親自試試?。?/p>

這是如何運(yùn)作的?事實(shí)證明,在調(diào)用構(gòu)造函數(shù)后,React也會(huì)在實(shí)例上分配props

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

因此,即使你忘記將props傳遞給super,React仍會(huì)在之后設(shè)置它們。這是有原因的。

當(dāng)React添加對(duì)類的支持時(shí),它不僅僅增加了對(duì)ES6類的支持。目標(biāo)是盡可能支持廣泛的類抽象。目前尚不清楚ClojureScript,CoffeeScript,ES6,Fable,Scala.jsTypeScript或其他解決方案在定義組件方面的成功程度。所以React故意不關(guān)心是否需要調(diào)用super - 即使是ES6類。

那么這是否意味著你可以只寫super()而不是super(props)?

盡可能不要這樣,否則會(huì)使人困惑。

當(dāng)然,React稍后會(huì)在你的構(gòu)造函數(shù)運(yùn)行后分配this.props。但是this.props在調(diào)用super和構(gòu)造函數(shù)結(jié)束之間仍然是未定義的:

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

// Inside your code
class Button extends React.Component {
  constructor(props) {
    super(); // ?? We forgot to pass props
    console.log(props);      // ? {}
    console.log(this.props); // ?? undefined 
  }
  // ...
}

如果在從構(gòu)造函數(shù)調(diào)用的某個(gè)方法中發(fā)生這種情況,則調(diào)試可能更具挑戰(zhàn)性。 這就是為什么我建議總是傳遞super(props),即使它不是絕對(duì)必要的:

class Button extends React.Component {
  constructor(props) {
    super(props); // ? We passed props
    console.log(props);      // ? {}
    console.log(this.props); // ? {}
  }
  // ...
}

這樣可以確保在構(gòu)造函數(shù)退出之前設(shè)置this.props。


最后一點(diǎn)React用戶可能會(huì)對(duì)此感到好奇。

您可能已經(jīng)注意到,當(dāng)您在類中使用Context API時(shí)(使用遺留的contextTypesReact 16.6中添加的現(xiàn)代contextType API),上下文將作為第二個(gè)參數(shù)傳遞給構(gòu)造函數(shù)。

那么為什么我們不寫super(props, context)呢?我們可以,但上下文的使用頻率較低,所以這個(gè)陷阱并沒有那么多。

隨著類字段的提議,這整個(gè)陷阱大多數(shù)都會(huì)消失。如果沒有顯式構(gòu)造函數(shù),則會(huì)自動(dòng)傳遞所有參數(shù)。這允許像state = {}這樣的表達(dá)式包含對(duì)this.propsthis.context的引用(如果需要)。

有了Hooks,我們甚至沒有superthis。但那是另一天的話題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作為一個(gè)合格的開發(fā)者,不要只滿足于編寫了可以運(yùn)行的代碼。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,687評(píng)論 1 33
  • React.js 小書學(xué)習(xí) 之 【使用 JSX 描述 UI 信息】 從 JSX 到頁(yè)面 過程圖解:JSX 到頁(yè)面過...
    zdlucky閱讀 1,452評(píng)論 0 20
  • 請(qǐng)教老師 巧言令色 鮮矣仁 這一章是告訴我們不要巧言令色 要正直實(shí)事求是 具有一顆仁心嗎?然而讀鄉(xiāng)黨篇時(shí) 感覺恭敬...
    周洲的日常閱讀 329評(píng)論 0 0
  • 2016.8.4主要是Activity生命周期的問題,解決在橫豎屏轉(zhuǎn)換時(shí)出現(xiàn)當(dāng)前問題被重置的BUG,學(xué)會(huì)LOG過濾...
    nbpzjy閱讀 701評(píng)論 0 1
  • 姓名:于幸欣 公司:揚(yáng)州市方圓建筑工程有限公司 【日精進(jìn)打卡第93天】 【知~學(xué)習(xí)】 《六項(xiàng)精進(jìn)》5遍共445遍 ...
    幸欣閱讀 159評(píng)論 0 0

友情鏈接更多精彩內(nèi)容