Jaka jest różnica między „super ()” i „super (rekwizyty)” w React, gdy używa się klas es6?

531

Gdy jest to ważne, aby przejść propsdo super()i dlaczego?

class MyComponent extends React.Component {
  constructor(props) {
    super(); // or super(props) ?
  }
}
Misza Moroszko
źródło
7
Dobre wytłumaczenie można także znaleźć na stronie przesadnie
reagującej .io

Odpowiedzi:

709

Jest tylko jeden powód, dla którego należy przejść propsdo super():

Gdy chcesz uzyskać dostęp this.propsdo konstruktora.

Przechodzący:

class MyComponent extends React.Component {    
    constructor(props) {
        super(props)

        console.log(this.props)
        // -> { icon: 'home', … }
    }
}

Nie przechodzi:

class MyComponent extends React.Component {    
    constructor(props) {
        super()

        console.log(this.props)
        // -> undefined

        // Props parameter is still available
        console.log(props)
        // -> { icon: 'home', … }
    }

    render() {
        // No difference outside constructor
        console.log(this.props)
        // -> { icon: 'home', … }
    }
}

Zauważ, że przechodząc lub nie przechodząc propsdo superma żadnego wpływu na późniejsze zastosowań this.propszewnątrz constructor. Oznacza to render, że shouldComponentUpdateprocedury obsługi zdarzeń zawsze mają do niego dostęp.

Jest to wyraźnie powiedziane w jednej Sophie Alpert w odpowiedzi na podobne pytanie.


Dokumentacja - Stan i cykl życia, Dodawanie stanu lokalnego do klasy, punkt 2 - zaleca:

Komponenty klasy powinny zawsze wywoływać konstruktor podstawowy za pomocą props.

Jednak nie podano żadnego powodu. Możemy spekulować, że dzieje się tak z powodu podklasy lub ze względu na kompatybilność w przyszłości.

(Dzięki @MattBrowne za link)

Robin Pokorny
źródło
16
Myślę, że masz rację, mimo że inne odpowiedzi zdobywają więcej głosów. this.propsjest undefinedchyba że przekazany do super(). Tak czy inaczej, nie wpływa później renderingu lub dostępności this.propsw render()funkcji.
Micros
3
@Rotareti, nie, właściwie reszta klasy nie zależy od tej konstrukcji, o to chodzi. Komponent odbiera rekwizyty w inny sposób niż przez parametr konstruktora. A ponieważ przekazujesz wstępne rekwizyty super, masz do nich odniesienie w konstruktorze.
Robin Pokorny
7
Zgodnie z dokumentacją React, zawsze powinieneś przejść propsdo super(): facebook.github.io/react/docs/… . Nie jestem pewien, dlaczego, skoro, jak wskazałeś, this.propsjest dostępny w inny sposób w jakikolwiek sposób ... być może polecają to dla przyszłej kompatybilności na wypadek, gdyby przyszłe wersje React mogły chcieć coś zrobić propsw konstruktorze?
Matt Browne
23
Może jestem po prostu otwierając puszkę Pandory tutaj, ale dlaczego kiedykolwiek przejść propsdo superkiedy, jak wspomniałem, propsparametr jest tam dostępne dla nas do wykorzystania wewnątrz konstruktora i this.propsdziała wszędzie? Czy w ogóle jest korzyść z używania this.propstylko po prostu props? Czy złą praktyką jest rozkładanie propsw konstruktorze? Chyba nadal nie widać przypadek, że kiedykolwiek trzeba przejść propsdo super, ale jestem gotów się założyć, że to tylko moja ignorancja, ha.
indiesquidge
9
Jeśli używasz super(props), możesz wywoływać metody this.props z konstruktora , na przykład this.doStuffUsingThisDotProps(), bez konieczności przekazywania parametru props do tych metod / funkcji. Właśnie napisałem konstruktor, który to robi, co, jak się wydaje, wymaga super(props)najpierw użycia , zgodnie z odpowiedziami na to pytanie.
Victor Zamanian
54

W tym przykładzie rozszerzasz React.Componentklasę i zgodnie ze specyfikacją ES2015 konstruktor klasy potomnej nie może korzystać z niego, thisdopóki super()nie zostanie wywołany; także konstruktory klasy ES2015 muszą wywoływać, super()jeśli są podklasami.

class MyComponent extends React.Component {
  constructor() {
    console.log(this); // Reference Error
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

Dla kontrastu:

class MyComponent extends React.Component {
  constructor() {
    super();
    console.log(this); // this logged to console
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

Więcej szczegółów zgodnie z tą doskonałą odpowiedzią na przepełnienie stosu

Możesz zobaczyć przykłady komponentów utworzonych przez rozszerzenie React.Componentklasy, które nie wywołują, super()ale zauważysz, że nie mają one constructor, dlatego nie jest to konieczne.

class MyOtherComponent extends React.Component {
  render() {
    return <div>Hi {this.props.name}</div>;
  }
}

Pewnym punktem zamieszania, który widziałem u niektórych programistów, z którymi rozmawiałem, jest to, że składniki, które nie mają, constructora zatem nie wywołują super()nigdzie, nadal są this.propsdostępne w render()metodzie. Pamiętaj, że ta reguła i ta potrzeba utworzenia thispowiązania constructordotyczy tylko constructor.

Dave
źródło
15
Bardzo dziękuję za odpowiedź, ale nie odpowiada na moje pierwotne pytanie (różnica między super()i super(props)).
Misha Moroshko,
46

Po przejściu propsdo superrekwizyty zostaną przypisane do this. Spójrz na następujący scenariusz:

constructor(props) {
    super();
    console.log(this.props) //undefined
}

Jakkolwiek, kiedy to robisz:

constructor(props) {
    super(props);
    console.log(this.props) //props will get logged.
}
Nahush Farkande
źródło
Najlepsza odpowiedź na liście.
Basavaraj Hadimani,
Ta odpowiedź jest w połowie poprawna. Ten przykład dotyczy tylko metody konstruktora. Na przykład, nawet jeśli nie napiszesz super (rekwizyty), this.props w metodzie renderowania będzie nadal przypisany i dostępny. Jedynym powodem wspomnianym powyżej jest użycie this.props w konstruktorze.
Ofear
12

Zgodnie z kodem źródłowym

function ReactComponent(props, context) {
  this.props = props;
  this.context = context;
}

musisz zdać za propskażdym razem, gdy masz rekwizyty i nie wkładasz ich this.propsręcznie.

zerkms
źródło
1
Nadal nie jestem tego pewien. jeśli spojrzysz na te dwa elementy , zobaczysz jedno połączenie, super(props)a drugie nie. Ale ich konsumenci ustawiają rekwizyty. Jaka jest różnica?
Kyeotic,
Czy to oznacza, że this.props = propsi super(props)to to samo?
reectrix
1
To nie jest prawda. ReactElement faktycznie ustawia się this.propsna „z zewnątrz” - niezależnie od tego, co dzieje się w konstruktorze.
Robin Pokorny
11

Dan Abramov napisał artykuł na ten temat:

Dlaczego piszemy super (rekwizyty)?

Istotą tego jest to, że warto mieć w zwyczaju przekazywanie go, aby uniknąć tego scenariusza, i szczerze mówiąc, nie widzę, aby miało to miejsce:

// 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 
  }
  // ...
}
Alfonso Pérez
źródło
8

super() służy do wywołania konstruktora nadrzędnego.

super(props)przejdzie propsdo konstruktora nadrzędnego.

Z twojego przykładu super(props)wywołałby React.Componentkonstruktor propsjako argument.

Więcej informacji na super: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super

kspence
źródło
18
Tak, właśnie to robi. Ale dlaczego ? A kiedy w React wymagana jest jedna z dwóch form?
Bergi
7

Podczas implementacji constructor()funkcji w komponencie React super()jest wymagane. Pamiętaj, że twój MyComponentelement rozszerza lub pożycza funkcjonalność z React.Componentklasy podstawowej.

Ta klasa bazowa ma własną constructor()funkcję, która zawiera w sobie trochę kodu, aby skonfigurować dla nas nasz komponent React.

Kiedy zdefiniujemy constructor() funkcję w naszej MyComponentklasie, w zasadzie zastępujemy lub zastępujemy constructor()funkcję wewnątrz React.Componentklasy, ale nadal musimy upewnić się, że cały kod instalacyjny w tej constructor()funkcji jest nadal wywoływany.

Tak aby zapewnić, że React.Component„sconstructor() funkcja jest wywoływana, nazywamy super(props). super(props)jest odniesieniem do constructor()funkcji rodziców , to wszystko.

Musimy dodawać za super(props)każdym razem, gdy definiujemy constructor()funkcję wewnątrz komponentu opartego na klasie.

Jeśli tego nie zrobimy, pojawi się błąd informujący, że musimy zadzwonić super(props).

Cały powód tego zdefiniowania constructor() jest zainicjowanie naszego obiektu stanu.

Aby więc zainicjować nasz obiekt stanu, pod super wywołaniem zamierzam napisać:

class App extends React.Component {
  constructor(props) {
      super(props);

      this.state = {};
   }

  // React says we have to define render()
  render() {
    return <div>Hello world</div>;
  }
};

Zdefiniowaliśmy więc naszą constructor()metodę, zainicjowaliśmy nasz obiekt stanu, tworząc obiekt JavaScript, przypisując mu właściwość lub parę klucz / wartość, przypisując wynik tej operacji this.state. Teraz oczywiście jest to tylko przykład, więc tak naprawdę nie przypisałem pary klucz / wartość do obiektu stanu, jest to po prostu pusty obiekt.

Daniel
źródło
4

Oto skrzypce, które zrobiłem: jsfiddle.net . Pokazuje, że rekwizyty domyślnie nie są przypisane do konstruktora. Jak rozumiem, są one oparte na metodzie React.createElement. Stąd super(props)powinna być wywoływana tylko kiedy assings ręcznie konstruktor nadklasy w propscelu this.props. Jeśli tylko przedłużysz React.Componentpołączenie super(props), nic nie zrobisz z rekwizytami. Może zostanie zmieniony w następnych wersjach React.

Beshanoe
źródło
3

Tutaj nie otrzymamy tego w konstruktorze, więc zwróci niezdefiniowane, ale będziemy mogli pobrać to poza funkcją konstruktora

class MyComponent extends React.Component {
  constructor() {
    console.log(this); // Reference Error i.e return undefined
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

Jeśli używamy super (), możemy pobrać również zmienną „this” wewnątrz konstruktora

class MyComponent extends React.Component {
  constructor() {
    super();
    console.log(this); // this logged to console
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

Więc kiedy używamy super (); będziemy mogli to pobrać, ale this.props będzie niezdefiniowany w konstruktorze. Ale oprócz konstruktora this.props nie zwróci niezdefiniowanego.

Jeśli użyjemy super (rekwizyty), możemy również użyć wartości this.props wewnątrz konstruktora

Odpowiedź Sophie Alpert

Jeśli chcesz użyć this.props w konstruktorze, musisz przekazać rekwizyty super. W przeciwnym razie nie ma to znaczenia, ponieważ React ustawia .props na instancję z zewnątrz natychmiast po wywołaniu konstruktora.

VIKAS KOHLI
źródło
3

Aby zareagować na wersję 16.6.3, używamy super (rekwizyty) do zainicjowania nazwy elementu stanu : this.props.name

constructor(props){
    super(props);        
}
state = {
  name:this.props.name 
    //otherwise not defined
};
Shubham Kapoor
źródło