React, ES6 - getInitialState був визначений у простому класі JavaScript


115

У мене є такий компонент ( 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>
         )
     }
 };

До використання ECMAScript6 все було добре, тепер я отримую 1 помилку, 1 попередження, і у мене є наступне питання:

Помилка: Uncaught TypeError: Неможливо прочитати властивість 'otherChecked' null

Попередження: getInitialState було визначено на RadioOther, простому класі JavaScript. Це підтримується лише для класів, створених за допомогою React.createClass. Ви мали натомість визначити власність держави?


  1. Хтось може бачити, де лежить помилка, я знаю, що це пов’язано з умовною заявою в DOM, але, мабуть, я не декларую своє початкове значення правильно?

  2. Чи варто робити getInitialState статичним

  3. Де відповідне місце для оголошення моїх підказок, якщо getInitialState невірний?

ОНОВЛЕННЯ:

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

   module.exports = RadioOther;

@ssorallen, цей код:

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

виробляє "Uncaught ReferenceError: this is not defined", а внизу виправляє це

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

але тепер, натиснувши на іншу кнопку, тепер виникає помилка:

Uncaught TypeError: Cannot read property 'props' of undefined


1
Інші зміни для класів ES6 є те , що методи не є «автоматично пов'язані» наприклад, маючи в увазі , коли ви передаєте функції , як onChange={this.onRadChange}, thisне відноситься до примірника , коли onRadChangeвикликається. Ви повинні зв'язати зворотні виклики в renderабо зробити це в конструкторі: onChange={this.onRadChange.bind(this)}.
Росс Аллен

Відповіді:


239
  • getInitialStateне використовується в класах ES6. Замість цього призначте this.stateв конструкторі.
  • propTypes повинна бути статичною змінною класу або присвоюватися класу, вона не повинна призначатися екземплярам компонентів.
  • Методи учасників не "автоматично пов'язані" в класах ES6. Для методів, що використовуються як зворотні виклики, використовуйте або ініціалізатори властивостей класу, або призначте пов'язані екземпляри в конструкторі.
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 = () => {
    ...
  };

  ...

}

Дивіться більше в документації React про класи ES6: Перетворення функції в клас


Через рік і тепер ви можете виявити: Uncaught TypeError: Cannot read property 'bind' of undefinedпомилка Будь-які ідеї?
Джеймі Хатбер

@JamieHutber Чи можете ви створити нове запитання зі своїм кодом? Якщо метод визначений у класі, я не знаю, чому ви отримаєте цю помилку.
Росс Аллен

Дякую за пропозицію, @KennethWorden. Я відкрив випуск для документів React: github.com/facebook/react/isissue/7746
Росс Аллен

Чи означає «зв’язати їх на місці», використовуючи функцію стрілки, як показано вище? Це, звичайно, працює. О, javascript!
jomofrodo

@jomofrodo Це неоднозначно, дякую, що вказали на це. Я мав на увазі, що у renderвас можна зробити щось на кшталт onClick={this.doFoo.bind(this)}, але я навмисно не включив це до коду, тому що це найменш ефективний спосіб зв’язування, оскільки його renderможуть викликати часто і створюватимуть нові функції під час кожного дзвінка. Я вилучу цю мову з відповіді.
Росс Аллен

4

Додавання до відповіді Росса .

Ви також можете використати нову функцію стрілки ES6 у властивості onChange

Він функціонально еквівалентний визначенню this.onRadChange = this.onRadChange.bind(this);в конструкторі, але на мою думку є більш стислим.

У вашому випадку перемикач буде мати вигляд нижче.

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

Оновлення

Цей "більш стислий" метод менш ефективний, ніж параметри, згадані у відповіді @Ross Allen, оскільки він генерує нову функцію щоразу, коли render()метод викликається


1
Це рішення є функціонально правильним, але воно створює нову функцію під час кожного виклику render(який можна було б викликати багато разів). Використовуючи ініціалізатор властивостей класу або прив'язку в конструкторі, при побудові компонента створюється лише одна нова прив’язана функція, і протягом цього часу не створюються нові функції render.
Росс Аллен

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.