React, ES6 - getInitialState è stato definito su una semplice classe JavaScript


115

Ho il seguente componente ( 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>
         )
     }
 };

Prima di utilizzare ECMAScript6 tutto andava bene, ora ricevo 1 errore, 1 avviso e ho una domanda di follow-up:

Errore: errore di tipo non rilevato: impossibile leggere la proprietà "otherChecked" di null

Avvertenza: getInitialState è stato definito su RadioOther, una semplice classe JavaScript. Questo è supportato solo per le classi create usando React.createClass. Intendevi invece definire una proprietà demaniale?


  1. Qualcuno può vedere dove si trova l'errore, so che è dovuto all'istruzione condizionale nel DOM ma a quanto pare non sto dichiarando correttamente il suo valore iniziale?

  2. Devo rendere statico getInitialState

  3. Dov'è il posto appropriato per dichiarare i miei proptypes se getInitialState non è corretto?

AGGIORNARE:

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

   module.exports = RadioOther;

@ssorallen, questo codice:

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

produce "Uncaught ReferenceError: this is not defined", e mentre sotto lo corregge

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

ma ora, facendo clic sull'altro pulsante ora si genera un errore:

Uncaught TypeError: Cannot read property 'props' of undefined


1
L'altra modifica per le classi ES6 è che i metodi non sono "auto-legati" all'istanza, il che significa che quando si passa una funzione simile onChange={this.onRadChange}, thisnon si fa riferimento all'istanza quando onRadChangeviene chiamata. Hai bisogno di callback legano in rendero farlo nel costruttore: onChange={this.onRadChange.bind(this)}.
Ross Allen

Risposte:


239
  • getInitialStatenon è utilizzato nelle classi ES6. Assegna invece this.statenel costruttore.
  • propTypes dovrebbe essere una variabile di classe statica o assegnata alla classe, non dovrebbe essere assegnata alle istanze del componente.
  • I metodi dei membri non sono "associati automaticamente" nelle classi ES6. Per i metodi utilizzati come callback, utilizzare gli inizializzatori di proprietà di classe o assegnare istanze associate nel costruttore.
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 = () => {
    ...
  };

  ...

}

Vedi di più nella documentazione di React sulle classi ES6: Conversione di una funzione in una classe


Un anno dopo e ora potresti scoprire che ricevi: Uncaught TypeError: Cannot read property 'bind' of undefinederrore Qualche idea?
Jamie Hutber

@JamieHutber Puoi creare una nuova domanda con il tuo codice? Se il metodo è definito sulla classe, non so perché dovresti ottenere quell'errore.
Ross Allen

Grazie per il suggerimento, @KennethWorden. Ho aperto un problema per i documenti di React: github.com/facebook/react/issues/7746
Ross Allen

"Legarli in posizione" significa utilizzare una funzione freccia come mostrato sopra? Funziona, ovviamente. Oh, javascript!
jomofrodo

@jomofrodo Questo è ambiguo, grazie per averlo sottolineato. Volevo dire renderche potresti fare qualcosa di simile onClick={this.doFoo.bind(this)}, ma intenzionalmente non l'ho incluso nel codice perché è il modo meno efficiente per eseguire il binding poiché renderpuò essere chiamato spesso e creerebbe nuove funzioni a ogni chiamata. Rimuoverò quella lingua dalla risposta.
Ross Allen

4

In aggiunta a Ross's risposta .

È inoltre possibile utilizzare la nuova funzione freccia ES6 sulla proprietà onChange

È funzionalmente equivalente a definire this.onRadChange = this.onRadChange.bind(this); nel costruttore ma è più conciso a mio parere.

Nel tuo caso il pulsante di opzione sarà simile al seguente.

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

Aggiornare

Questo metodo "più conciso" è meno efficiente delle opzioni menzionate nella risposta di @Ross Allen perché genera una nuova funzione ogni volta che il render()metodo viene chiamato


1
Questa soluzione è funzionalmente corretta, ma crea una nuova funzione su ogni chiamata a render(che potrebbe essere chiamata molte volte). Utilizzando un inizializzatore di proprietà di classe o un'associazione nel costruttore, viene creata solo una nuova funzione associata alla costruzione del componente e durante la creazione non vengono create nuove funzioni render.
Ross Allen

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.