React, ES6 - getInitialState wurde in einer einfachen JavaScript-Klasse definiert

115

Ich habe die folgende Komponente ( radioOther.jsx):

 'use strict';

 //module.exports = <-- omitted in update

   class RadioOther extends React.Component {

     // omitted in update 
     // getInitialState() {
     //    propTypes: {
     //        name: React.PropTypes.string.isRequired
     //    }
     //    return {
     //       otherChecked: false
     //   }
     // }

     componentDidUpdate(prevProps, prevState) {
         var otherRadBtn = this.refs.otherRadBtn.getDOMNode();

         if (prevState.otherChecked !== otherRadBtn.checked) {
             console.log('Other radio btn clicked.')
             this.setState({
                 otherChecked: otherRadBtn.checked,
             });
         }
     }

     onRadChange(e) {
         var input = e.target;
         this.setState({
             otherChecked: input.checked
         });
     }

     render() {
         return (
             <div>
                 <p className="form-group radio">
                     <label>
                         <input type="radio"
                                ref="otherRadBtn"
                                onChange={this.onRadChange}
                                name={this.props.name}
                                value="other"/>
                         Other
                     </label>
                     {this.state.otherChecked ?
                         (<label className="form-inline">
                             Please Specify:
                             <input
                                 placeholder="Please Specify"
                                 type="text"
                                 name="referrer_other"
                                 />
                         </label>)
                         :
                         ('')
                     }
                 </p>
             </div>
         )
     }
 };

Vor der Verwendung von ECMAScript6 war alles in Ordnung, jetzt erhalte ich 1 Fehler, 1 Warnung und ich habe eine Folgefrage:

Fehler: Nicht erfasst TypeError: Die Eigenschaft 'otherChecked' von null kann nicht gelesen werden

Warnung: getInitialState wurde in RadioOther definiert, einer einfachen JavaScript-Klasse. Dies wird nur für Klassen unterstützt, die mit React.createClass erstellt wurden. Wollten Sie stattdessen eine Staatseigenschaft definieren?


  1. Kann jemand sehen, wo der Fehler liegt, ich weiß, dass es an der bedingten Anweisung im DOM liegt, aber anscheinend deklariere ich seinen Anfangswert nicht richtig?

  2. Soll ich getInitialState statisch machen ?

  3. Wo kann ich meine Proptypen deklarieren, wenn getInitialState nicht korrekt ist?

AKTUALISIEREN:

   RadioOther.propTypes = {
       name: React.PropTypes.string,
       other: React.PropTypes.bool,
       options: React.PropTypes.array }

   module.exports = RadioOther;

@ssorallen, dieser Code:

     constructor(props) {
         this.state = {
             otherChecked: false,
         };
     }

produziert "Uncaught ReferenceError: this is not defined", und während unten korrigiert das

     constructor(props) {
     super(props);
         this.state = {
             otherChecked: false,
         };
     }

Wenn Sie jetzt auf die andere Schaltfläche klicken, wird ein Fehler angezeigt:

Uncaught TypeError: Cannot read property 'props' of undefined

Talha Awan
quelle
1
Die andere Änderung für ES6 Klassen ist , dass Methoden nicht „Auto-gebunden“ an die Instanz, was bedeutet , wenn Sie eine Funktion wie passieren onChange={this.onRadChange}, thisbezieht sich nicht auf die Instanz , wenn onRadChangeaufgerufen wird. Sie müssen Rückrufe einbinden renderoder im Konstruktor ausführen : onChange={this.onRadChange.bind(this)}.
Ross Allen

Antworten:

239
  • getInitialStatewird in ES6-Klassen nicht verwendet. Weisen Sie stattdessen this.stateim Konstruktor zu.
  • propTypes sollte eine statische Klassenvariable sein oder der Klasse zugewiesen sein, sollte sie nicht Komponenteninstanzen zugewiesen werden.
  • Mitgliedsmethoden sind in ES6-Klassen nicht "automatisch gebunden" . Verwenden Sie für Methoden, die als Rückrufe verwendet werden, entweder Initialisierer für Klasseneigenschaften oder weisen Sie gebundene Instanzen im Konstruktor zu.
export default class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      otherChecked: false,
    };
  }

  // Class property initializer. `this` will be the instance when
  // the function is called.
  onRadChange = () => {
    ...
  };

  ...

}

Weitere Informationen finden Sie in der React-Dokumentation zu ES6-Klassen: Konvertieren einer Funktion in eine Klasse

Ross Allen
quelle
Ein Jahr später und jetzt werden Sie vielleicht feststellen: Uncaught TypeError: Cannot read property 'bind' of undefinedFehler Irgendwelche Ideen?
Jamie Hutber
@JamieHutber Können Sie mit Ihrem Code eine neue Frage erstellen? Wenn die Methode für die Klasse definiert ist, weiß ich nicht, warum Sie diesen Fehler erhalten würden.
Ross Allen
Danke für den Vorschlag, @KennethWorden. Ich habe eine Ausgabe für die React-Dokumente geöffnet: github.com/facebook/react/issues/7746
Ross Allen
Bedeutet "Binden Sie sie an Ort und Stelle", dass Sie eine Pfeilfunktion verwenden, wie Sie oben gezeigt haben? Das funktioniert natürlich. Oh, Javascript!
Jomofrodo
@jomofrodo Das ist mehrdeutig, danke für den Hinweis. Ich meinte, renderSie könnten so etwas tun onClick={this.doFoo.bind(this)}, aber ich habe es absichtlich nicht in den Code aufgenommen, da dies die am wenigsten effiziente Art des Bindens ist, da renderes häufig aufgerufen werden kann und bei jedem Aufruf neue Funktionen erstellen würde. Ich werde diese Sprache aus der Antwort entfernen.
Ross Allen
4

Hinzufügen zu Ross ' Antwort.

Sie können auch die neue ES6- Pfeilfunktion für die onChange-Eigenschaft verwenden

Es entspricht funktional der Definition this.onRadChange = this.onRadChange.bind(this);im Konstruktor, ist aber meiner Meinung nach prägnanter.

In Ihrem Fall sieht das Optionsfeld wie folgt aus.

<input type="radio"
       ref="otherRadBtn"
       onChange={(e)=> this.onRadChange(e)}
       name={this.props.name}
       value="other"/>

Aktualisieren

Diese "präzisere" Methode ist weniger effizient als die in der Antwort von @Ross Allen genannten Optionen, da sie bei jedem render()Aufruf der Methode eine neue Funktion generiert

Sudarshan
quelle
1
Diese Lösung ist funktional korrekt, erstellt jedoch bei jedem Aufruf von eine neue Funktion render(die häufig aufgerufen werden kann). Durch Verwendung eines Klasseneigenschaftsinitialisierers oder einer Bindung im Konstruktor wird beim Erstellen der Komponente nur eine neue gebundene Funktion erstellt, und währenddessen werden keine neuen Funktionen erstellt render.
Ross Allen
1

Wenn Sie babel-plugin-transform-class-properties oder babel-preset-stage-2 (oder stage-1 oder stage-0) verwenden, können Sie diese Syntax verwenden:

class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string,
    ...
  };

  state = {
      otherChecked: false,
  };

  onRadChange = () => {
    ...
  };

  ...

}
Seen sind
quelle