Prečo používame super(props)?
2018 M11 30 • ☕️ 4 min read
Translated by readers into: Deutsch • Español • Français • Italiano • Magyar • Nederlands • Norsk • Português do Brasil • Slovenčina • Tiếng Việt • Türkçe • srpski • Čeština • Українська • فارسی • ไทย • မြန်မာဘာသာ • 日本語 • 简体中文 • 繁體中文
Read the original • Improve this translation • View all translated posts
Vraj je funkcia Hooks v Reacte trendy. Ale blog začínam vysvetlením ako fungujú komponenty vytvorené pomocou triedy.
Tieto veci nie sú dôležité na to, aby ste boli produktívni pri používaní Reactu. Ale budete radi ak viete, ako veci fungujú.
Tu je prvý príspevok.
Do kódu som napísal super(props)
toľkokrát, že už to ani nerátam:
class Checkbox extends React.Component {
constructor(props) {
super(props); this.state = { isOn: true };
}
// ...
}
Samozrejme, nemusíme to robiť, keď použijeme vlastnosti triedy:
class Checkbox extends React.Component {
state = { isOn: true };
// ...
}
Syntax podobná tomuto bola v Reacte plánovaná už vo verzii 0.13, ktorý pridal podporu pre triedy v roku 2015. Použitie konštruktora a super(props)
bolo len dočasným riešením dokiaľ vlastnosti triedy neposkytli pohodlnejšiu alternatívu.
Ale vráťme sa k príkladu, ktorý používa iba funkcie štandardu ES2015:
class Checkbox extends React.Component {
constructor(props) {
super(props); this.state = { isOn: true };
}
// ...
}
Prečo vlastne používame funkciu super
? Môžeme ju nepoužívať? Ak ju musíme používať, čo sa stane keď jej neposkytneme props
? Používajú sa aj iné parametre? Pozrime sa na to…
V JavaScripte je funkcia super
konštruktor triedy, ktorú rozširujeme. (V tomto príklade sa jedná o implementáciu React.Component
.)
Je dôležité vedieť, že v konštruktore nemôžeme používať this
dovtedy, pokým nepoužijeme funkciu super
:
class Checkbox extends React.Component {
constructor(props) {
// 🔴 Nemôžeme používať `this`
super(props);
// ✅ Až teraz môžeme používať `this`
this.state = { isOn: true };
}
// ...
}
Existuje dobrý dôvod, prečo JavaScript chce, aby sme zavolali konštruktor rozširovanej triedy predtým, než použijeme this
. Predstavme si hierarchiu:
class Person {
constructor(name) {
this.name = name;
}
}
class PolitePerson extends Person {
constructor(name) {
this.greetColleagues(); // 🔴 Toto sa nesmie
super(name);
}
greetColleagues() {
alert('Dobrý deň, priatelia!');
}
}
Teraz si predstavme, že použijeme this
pred funkciou super
. O mesiac neskôr chceme zmeniť funkciu greetColleagues
tak, aby v správe bolo meno dotyčnej osoby:
greetColleagues() {
alert('Dobrý deň, priatelia!');
alert('Teší ma, volám sa ' + this.name + '!');
}
Dovtedy sme už aj zabudli, že funkcia this.greetColleagues()
bola použitá predtým, než funkcia super()
definovala this.name
. To znamená, že vlastnosť this.name
nie je definovaná! Ako vidíte, pri takom kóde sa veľmi ťažko premýšľa.
Preto JavaScript chce, aby sme zavolali super
predtým, než použijeme this
. Nech si trieda, ktorá bola rozšírená, robí čo len chce! To obmedzenie platí aj na komponenty, ktoré sú definované pomocou triedy:
constructor(props) {
super(props);
// ✅ Až teraz môžeme používať `this`
this.state = { isOn: true };
}
Z toho vyplýva ďalšia otázka: prečo poskytujeme funkcii super
parameter props
?
Aby mohol konštruktor triedy React.Component
nastaviť this.props
, mali by sme poskytnúť funkcii super
parameter props
:
// Vo vnútri Reactu
class Component {
constructor(props) {
this.props = props;
// ...
}
}
Ale aj keby sme zavolali funkciu super()
bez parametra props
, stále by sme vedeli používať this.props
v metódach ako je render
a podobne. (Neveríte? Vyskúšajte to!)
Ako to je možné, že to funguje? React nastavuje props
hneď potom, ako použije váš konštruktor:
// Vo vnútri Reactu
const instance = new YourComponent(props);
instance.props = props;
Takže aj keď zabudneme poskytnúť props
funkcii super()
, React ich nastaví. Aj na to je dôvod.
Keď React pridal podporu pre triedy, nepridal podporu iba pre ES6. Cieľom bolo pridať podporu pre čo najviac abstrakcii triedy. A vtedy nebolo jasné, ako úspešné budú jazyky ako sú ClojureScript, CoffeeScript, ES6, Fable, Scala.js alebo TypeScript. React bol zámerne nestranný, a nevyžadoval použitie funkcie super()
— aj keď sú triedy štandardu ES6 iné.
Znamená to, že môžeme používať super()
namiesto super(props)
?
Ani nie, pretože je to mätúce. Áno, React nastaví this.props
potom, ako bol váš konštruktor spustený. Lenže od zavolania funkcie super
až po koniec konštruktora nebude this.props
definovaný:
// Vo vnútri Reactu
class Component {
constructor(props) {
this.props = props;
// ...
}
}
// Vo vašom kóde
class Button extends React.Component {
constructor(props) {
super(); // 😬 Zabudli sme na props
console.log(props); // ✅ {}
console.log(this.props); // 😬 undefined }
// ...
}
A je výzvou opraviť chybu, ktorá nastane, keď je nejaká funkcia volaná v konštruktore. Práve preto vždy odporúčam používať super(props)
:
class Button extends React.Component {
constructor(props) {
super(props); // ✅ Posktyli sme props
console.log(props); // ✅ {}
console.log(this.props); // ✅ {}
}
// ...
}
Vďaka tomu bude this.props
dostupný ešte predtým, než bude konštruktor ukončený.
Je ešte jedna vec, o ktorú sa môžu zaujímať dlhodobí používatelia Reactu.
Mohli ste si všimnúť, že keď sa v triede použije Context API (či už pomocou zastaralého contextTypes
alebo moderného contextType
, pridaného vo verzii 16.6), context
je druhým parametrom konštruktora.
Prečo teda nepoužívame super(props, context)
? Môžeme, ale context
sa nepoužíva až tak často.
Vďaka vlastnostiam triedy je tento problém vyriešený. Bez daného konštruktora sú všetky parametre dané rozširovanej triede. Kvôli tomu môže state = {}
použiť this.props
alebo this.context
.
Keď používame funkciu Hooks, nepoužívame ani super
, ani this
. Ale to je téma do budúcna.